Input: remotes and gamepads
Every platform’s input arrives as DOM keyboard events, because SDL has already normalised the hardware:
| Hardware | Arrives as |
|---|---|
| tvOS Siri Remote | arrows, Enter (select), Escape (Menu) |
| Android TV / Fire TV remote | arrows, Enter (D-pad centre), AC Back, media keys |
| macOS / Linux keyboard | a keyboard |
| Game controllers | keys, until you claim them (below) |
Each becomes a keydown / keyup with key, code and the legacy keyCode that TV frameworks
still key on — Blits and Lightning read 37–40 for the arrows, 13 for enter and 8 for back.
window.addEventListener('keydown', (e) => { switch (e.key) { case 'ArrowRight': focusNext(); break case 'Enter': activate(); break case 'Escape': goBack(); break // tvOS Menu, Android Back }})Gamepads
Section titled “Gamepads”Gamepads are the W3C Gamepad API in the standard mapping. gamepadconnected and
gamepaddisconnected are trusted GamepadEvents at window, fired as tasks that a pause holds
rather than drops — a controller connecting is a fact the page needs after it resumes.
window.addEventListener('gamepadconnected', (e) => { console.log(e.gamepad.index, e.gamepad.id)})
function frame () { const [pad] = navigator.getGamepads() if (pad?.buttons[0].pressed) jump() requestAnimationFrame(frame)}Input follows focus
Section titled “Input follows focus”Keys go to the focused browsing context and to nothing else. When a launcher calls focus() on an
<iframe>, the launcher stops receiving input and the instance starts. A focus switch releases keys
that were held, the way a controller disconnecting mid-press does, so no context is left with a key
down it will never see go up.
Leaving the app
Section titled “Leaving the app”window.close() calls the host’s exit path where the host defines one — the Android host finishes the
activity. On tvOS, the Menu button at the app’s root does not yet exit to the Home screen; the
JavaScript-visible way out is the app’s own window.close() call rather than a guess about Back.