Add virtual gamepad controls and fullscreen toggle for webxdc games

This commit is contained in:
Chad Curtis
2026-02-23 00:57:42 -06:00
parent 986dffadda
commit 79d366b240
2 changed files with 26 additions and 11 deletions
+20
View File
@@ -3062,6 +3062,7 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3075,6 +3076,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3088,6 +3090,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3101,6 +3104,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3114,6 +3118,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3127,6 +3132,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3140,6 +3146,7 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3153,6 +3160,7 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3166,6 +3174,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3179,6 +3188,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3192,6 +3202,7 @@
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3205,6 +3216,7 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3218,6 +3230,7 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3231,6 +3244,7 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3244,6 +3258,7 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3257,6 +3272,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3270,6 +3286,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3283,6 +3300,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3296,6 +3314,7 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3309,6 +3328,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
+6 -11
View File
@@ -28,14 +28,8 @@ export function WebxdcEmbed({ url, uuid, name, icon, className }: WebxdcEmbedPro
const [isFullscreen, setIsFullscreen] = useState(false);
const [iframeKey, setIframeKey] = useState(0);
const [showGamepad, setShowGamepad] = useState(false);
const [webxdcHandle, setWebxdcHandle] = useState<WebxdcHandle | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
// Callback ref: when the Webxdc component mounts, store the handle in state
// so GameControls re-renders with a non-null handle.
const webxdcHandleCallback = useCallback((handle: WebxdcHandle | null) => {
setWebxdcHandle(handle);
}, []);
const webxdcHandleRef = useRef<WebxdcHandle>(null);
// Derive a stable iframe ID from the UUID or URL
const iframeId = uuid ?? url.replace(/[^a-zA-Z0-9]/g, '').slice(0, 32);
@@ -56,10 +50,10 @@ export function WebxdcEmbed({ url, uuid, name, icon, className }: WebxdcEmbedPro
const toggleGamepad = useCallback(() => {
setShowGamepad((prev) => {
if (!prev) webxdcHandle?.focus();
if (!prev) webxdcHandleRef.current?.focus();
return !prev;
});
}, [webxdcHandle]);
}, []);
if (!launched) {
return (
@@ -208,7 +202,7 @@ export function WebxdcEmbed({ url, uuid, name, icon, className }: WebxdcEmbedPro
<div className={cn(isFullscreen ? 'flex-1 relative' : 'relative')}>
<WebxdcIframe
key={iframeKey}
ref={webxdcHandleCallback}
ref={webxdcHandleRef}
id={iframeId}
url={url}
uuid={uuid}
@@ -222,7 +216,7 @@ export function WebxdcEmbed({ url, uuid, name, icon, className }: WebxdcEmbedPro
'border-t border-border bg-background/80 backdrop-blur-sm',
isFullscreen ? '' : 'rounded-b-2xl',
)}>
<GameControls webxdcHandle={webxdcHandle} />
<GameControls webxdcHandle={webxdcHandleRef.current} />
</div>
)}
</div>
@@ -247,6 +241,7 @@ const WebxdcIframe = forwardRef<WebxdcHandle, {
id={id}
xdc={url}
webxdc={webxdc}
allow="autoplay; fullscreen; gamepad"
className="w-full border-0"
style={{ height: isFullscreen ? '100%' : '400px' }}
/>