feat(playground): expand gamepad support with face buttons and Steam Deck fixes

- Map A=Train, B=Clear Examples, X=Randomize, LB=Thumbs Down, RB=Thumbs Up
- Add periodic gamepad polling fallback for environments where
  gamepadconnected event doesn't fire reliably (Steam Deck, some Linux browsers)
- Show "Press any gamepad button to connect" hint on page load
This commit is contained in:
w1n5t0n 2026-03-22 22:40:15 +02:00
parent affec8f604
commit de75a3f0e4
4 changed files with 50 additions and 17 deletions

View file

@ -1365,14 +1365,23 @@ function wireGamepad() {
onJoystickMove();
},
onButton: (btn) => {
if (btn === 'rb') onThumbsUp();
if (btn === 'lb') onThumbsDown();
if (btn === 'rb') onThumbsUp();
if (btn === 'a') onTrain();
if (btn === 'x') onRandomize();
if (btn === 'b') onClearExamples();
},
onConnectionChange: (connected) => {
const el = document.getElementById('gamepad-status');
if (el) el.textContent = connected ? 'Gamepad connected' : '';
if (el) el.textContent = connected ? 'Gamepad connected' : 'Press any button to activate gamepad';
},
});
// Show hint immediately if no gamepad detected yet
if (!gamepad.connected) {
const el = document.getElementById('gamepad-status');
if (el) el.textContent = 'Press any gamepad button to connect';
}
}
// ---- Keyboard ----

View file

@ -1241,15 +1241,23 @@ function init() {
mappingView.drawOverlay();
},
onButton: (btn) => {
if (btn === 'rb') onThumbsUp();
if (btn === 'lb') onThumbsDown();
if (btn === 'rb') onThumbsUp();
if (btn === 'a') onTrain();
if (btn === 'x') onRandomize();
if (btn === 'b') onClearExamples();
},
onConnectionChange: (connected) => {
const el = document.getElementById('gamepad-status');
if (el) el.textContent = connected ? 'Gamepad connected' : '';
if (el) el.textContent = connected ? 'Gamepad connected' : 'Press any button to activate gamepad';
},
});
if (!gamepad.connected) {
const el = document.getElementById('gamepad-status');
if (el) el.textContent = 'Press any gamepad button to connect';
}
// Resize
window.addEventListener('resize', () => {
visualizer.resize();

View file

@ -287,15 +287,20 @@ function init() {
drawJoystick();
},
onButton: (btn) => {
if (btn === 'rb') onThumbsUp();
if (btn === 'lb') onThumbsDown();
if (btn === 'rb') onThumbsUp();
},
onConnectionChange: (connected) => {
const el = document.getElementById('gamepad-status');
if (el) el.textContent = connected ? 'Gamepad connected' : '';
if (el) el.textContent = connected ? 'Gamepad connected' : 'Press any button to activate gamepad';
},
});
if (!gamepad.connected) {
const el = document.getElementById('gamepad-status');
if (el) el.textContent = 'Press any gamepad button to connect';
}
// Follow mode wiring
wireFollowMode();

View file

@ -37,6 +37,17 @@ export class GamepadInput {
// Check if a gamepad is already connected
this._findGamepad();
// Periodic fallback: some environments (Steam Deck, some Linux browsers)
// don't fire gamepadconnected reliably. Poll every 500ms until found.
this._probeInterval = setInterval(() => {
if (!this.connected) {
this._findGamepad();
} else {
clearInterval(this._probeInterval);
this._probeInterval = null;
}
}, 500);
}
_onConnected(e) {
@ -126,18 +137,17 @@ export class GamepadInput {
this.onMove(mappedX, mappedY);
}
// Buttons: LB=4, RB=5
// Buttons: A=0, B=1, X=2, Y=3, LB=4, RB=5
if (this.onButton) {
const lbPressed = !!gp.buttons[4]?.pressed;
const rbPressed = !!gp.buttons[5]?.pressed;
const lbPrev = !!this._buttonsPrev[4];
const rbPrev = !!this._buttonsPrev[5];
if (lbPressed && !lbPrev) this.onButton('lb');
if (rbPressed && !rbPrev) this.onButton('rb');
this._buttonsPrev[4] = lbPressed;
this._buttonsPrev[5] = rbPressed;
const watched = [0, 1, 2, 3, 4, 5];
const names = ['a', 'b', 'x', 'y', 'lb', 'rb'];
for (let i = 0; i < watched.length; i++) {
const idx = watched[i];
const pressed = !!gp.buttons[idx]?.pressed;
const prev = !!this._buttonsPrev[idx];
if (pressed && !prev) this.onButton(names[i]);
this._buttonsPrev[idx] = pressed;
}
}
return moved;
@ -153,5 +163,6 @@ export class GamepadInput {
destroy() {
window.removeEventListener('gamepadconnected', this._onConnected);
window.removeEventListener('gamepaddisconnected', this._onDisconnected);
if (this._probeInterval) clearInterval(this._probeInterval);
}
}