64 lines
1.6 KiB
TypeScript
64 lines
1.6 KiB
TypeScript
////
|
|
// 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)
|
|
} |