diff options
| author | Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> | 2025-07-21 13:24:11 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-21 13:24:11 -0400 |
| commit | 2106ef8eb31ee46611fce07dd715d3ac1c4ca0ab (patch) | |
| tree | 98f3ef8c841b341ea63d3055a460b4ff8e171815 /src | |
| parent | a7fb5ee69c8d74534f2994263558ddcd9c8c0d41 (diff) | |
| parent | 0dd6b54e6992f6d71a920a7b8bd8ca84672db145 (diff) | |
| download | decky-lsfg-vk-2106ef8eb31ee46611fce07dd715d3ac1c4ca0ab.tar.gz decky-lsfg-vk-2106ef8eb31ee46611fce07dd715d3ac1c4ca0ab.zip | |
Merge pull request #62 from xXJSONDeruloXx/clipboard-tests
Clipboard automation
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/ClipboardButton.tsx | 6 | ||||
| -rw-r--r-- | src/components/Content.tsx | 7 | ||||
| -rw-r--r-- | src/components/SmartClipboardButton.tsx | 124 | ||||
| -rw-r--r-- | src/components/UsageInstructions.tsx | 2 | ||||
| -rw-r--r-- | src/components/index.ts | 2 |
5 files changed, 133 insertions, 8 deletions
diff --git a/src/components/ClipboardButton.tsx b/src/components/ClipboardButton.tsx index 7fd0a9b..cac1863 100644 --- a/src/components/ClipboardButton.tsx +++ b/src/components/ClipboardButton.tsx @@ -1,5 +1,5 @@ import { PanelSectionRow, ButtonItem } from "@decky/ui"; -import { FaClipboard } from "react-icons/fa"; +import { FaBook } from "react-icons/fa"; export function ClipboardButton() { const handleClipboardClick = () => { @@ -13,8 +13,8 @@ export function ClipboardButton() { onClick={handleClipboardClick} > <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> - <FaClipboard /> - <div>Launch Option Clipboard</div> + <FaBook /> + <div>Plugin Wiki</div> </div> </ButtonItem> </PanelSectionRow> diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 9ce4c35..a075574 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -8,6 +8,7 @@ import { ConfigurationSection } from "./ConfigurationSection"; import { UsageInstructions } from "./UsageInstructions"; import { WikiButton } from "./WikiButton"; import { ClipboardButton } from "./ClipboardButton"; +import { SmartClipboardButton } from "./SmartClipboardButton"; import { PluginUpdateChecker } from "./PluginUpdateChecker"; import { NerdStuffModal } from "./NerdStuffModal"; import { ConfigurationData } from "../config/configSchema"; @@ -70,6 +71,8 @@ export function Content() { isInstalled={isInstalled} installationStatus={installationStatus} /> + + <SmartClipboardButton /> {/* Configuration Section - only show if installed */} {isInstalled && ( @@ -85,9 +88,7 @@ export function Content() { <ClipboardButton /> {/* Plugin Update Checker */} - <PluginUpdateChecker /> - - {/* Nerd Stuff Button */} + <PluginUpdateChecker /> {/* Nerd Stuff Button */} <PanelSectionRow> <ButtonItem layout="below" diff --git a/src/components/SmartClipboardButton.tsx b/src/components/SmartClipboardButton.tsx new file mode 100644 index 0000000..81223bd --- /dev/null +++ b/src/components/SmartClipboardButton.tsx @@ -0,0 +1,124 @@ +import { useState } from "react"; +import { PanelSectionRow, ButtonItem } from "@decky/ui"; +import { FaClipboard } from "react-icons/fa"; +import { toaster } from "@decky/api"; +import { getLaunchOption } from "../api/lsfgApi"; + +export function SmartClipboardButton() { + const [isLoading, setIsLoading] = useState(false); + + const getLaunchOptionText = async (): Promise<string> => { + try { + const result = await getLaunchOption(); + return result.launch_option || "~/lsfg %command%"; + } catch (error) { + return "~/lsfg %command%"; + } + }; + + const copyToClipboard = async () => { + if (isLoading) return; + + setIsLoading(true); + try { + const text = await getLaunchOptionText(); + + // Use the proven input simulation method + 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 copying using execCommand first (most reliable in gaming mode) + let copySuccess = false; + try { + if (document.execCommand('copy')) { + copySuccess = true; + } + } catch (e) { + // If execCommand fails, try navigator.clipboard as fallback + try { + await navigator.clipboard.writeText(text); + copySuccess = true; + } catch (clipboardError) { + console.error('Both copy methods failed:', e, clipboardError); + } + } + + // Clean up + document.body.removeChild(tempInput); + + if (copySuccess) { + // Verify the copy worked by reading back + try { + const readBack = await navigator.clipboard.readText(); + if (readBack === text) { + toaster.toast({ + title: "Copied to Clipboard!", + body: "Launch option ready to paste" + }); + } else { + // Copy worked but verification failed - still consider it success + toaster.toast({ + title: "Copied to Clipboard!", + body: "Launch option copied (verification unavailable)" + }); + } + } catch (e) { + // Verification failed but copy likely worked + toaster.toast({ + title: "Copied to Clipboard!", + body: "Launch option copied successfully" + }); + } + } else { + toaster.toast({ + title: "Copy Failed", + body: "Unable to copy to clipboard" + }); + } + + } catch (error) { + toaster.toast({ + title: "Copy Failed", + body: `Error: ${String(error)}` + }); + } finally { + setIsLoading(false); + } + }; + + return ( + <PanelSectionRow> + <ButtonItem + layout="below" + onClick={copyToClipboard} + disabled={isLoading} + > + <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> + {isLoading ? ( + <FaClipboard style={{ + animation: "pulse 1s ease-in-out infinite", + opacity: 0.7 + }} /> + ) : ( + <FaClipboard /> + )} + <div>{isLoading ? "Copying..." : "Copy Launch Option"}</div> + </div> + </ButtonItem> + <style>{` + @keyframes pulse { + 0% { opacity: 0.7; } + 50% { opacity: 1; } + 100% { opacity: 0.7; } + } + `}</style> + </PanelSectionRow> + ); +} diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx index 6025241..bcf258b 100644 --- a/src/components/UsageInstructions.tsx +++ b/src/components/UsageInstructions.tsx @@ -33,7 +33,7 @@ export function UsageInstructions({ config }: UsageInstructionsProps) { whiteSpace: "pre-wrap" }} > - Add the launch option below (or use "Launch Option Clipboard") to Steam games to activate frame generation. + Click "Copy Launch Option" button, then paste it into your Steam game's launch options to enable frame generation. </div> </PanelSectionRow> diff --git a/src/components/index.ts b/src/components/index.ts index c0c4804..682598c 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -4,7 +4,7 @@ export { InstallationButton } from "./InstallationButton"; export { ConfigurationSection } from "./ConfigurationSection"; // export { UsageInstructions } from "./UsageInstructions"; export { WikiButton } from "./WikiButton"; -export { ClipboardButton } from "./ClipboardButton"; +export { SmartClipboardButton } from "./SmartClipboardButton"; export { LaunchOptionInfo } from "./LaunchOptionInfo"; export { PluginUpdateChecker } from "./PluginUpdateChecker"; export { NerdStuffModal } from "./NerdStuffModal"; |
