gamepad support

This commit is contained in:
Chris Wanstrath 2025-09-29 14:56:47 -07:00
parent 815a589b23
commit 0c4c6fe58c
2 changed files with 66 additions and 0 deletions

64
app/src/js/gamepad.ts Normal file
View File

@ -0,0 +1,64 @@
////
// Support for gamepads.
// Maps incoming gamepad button presses to keyboard buttons.
//
const BUTTONS = [
"A", "B", "X", "Y",
"LB", "RB", "LT", "RT",
"Select", "Start",
"LStick", "RStick",
"DPad Up", "DPad Down", "DPad Left", "DPad Right"
]
const BUTTONS_TO_KEYS: Record<number, string> = {
0: "z", // A → Z
1: "x", // B → X
2: "c", // X → C
3: "v", // Y → V
12: "ArrowUp",
13: "ArrowDown",
14: "ArrowLeft",
15: "ArrowRight",
9: "Enter", // Start
8: "Escape" // Select
}
const activePads = new Set<number>()
const prevState: Record<number, boolean[]> = {}
export function initGamepad() {
window.addEventListener("gamepadconnected", e => {
console.log("Gamepad connected:", e.gamepad)
activePads.add(e.gamepad.index)
requestAnimationFrame(handleGamepad)
})
window.addEventListener("gamepaddisconnected", e => {
console.log("Gamepad disconnected:", e.gamepad)
activePads.delete(e.gamepad.index)
})
}
function handleGamepad() {
const pads = navigator.getGamepads()
for (const gp of pads) {
if (!gp) continue
if (!prevState[gp.index]) prevState[gp.index] = gp.buttons.map(() => false)
gp.buttons.forEach((btn, i) => {
const was = prevState[gp.index]![i]
const is = btn.pressed
if (was !== is) {
const key = BUTTONS_TO_KEYS[i]
if (key) {
const type = is ? "keydown" : "keyup"
window.dispatchEvent(new KeyboardEvent(type, { code: key, key }))
}
prevState[gp.index]![i] = is
}
})
}
requestAnimationFrame(handleGamepad)
}

View File

@ -2,6 +2,7 @@ import { initCompletion } from "./completion.js"
import { initCursor } from "./cursor.js"
import { initEditor } from "./editor.js"
import { initFocus } from "./focus.js"
import { initGamepad } from "./gamepad.js"
import { initHistory } from "./history.js"
import { initHyperlink } from "./hyperlink.js"
import { initInput } from "./input.js"
@ -13,6 +14,7 @@ initCompletion()
initCursor()
initFocus()
initEditor()
initGamepad()
initHistory()
initHyperlink()
initInput()