| |
| |
| |
| |
| |
|
|
| const KEYMAP = { |
| ArrowUp: "fwd", KeyW: "fwd", |
| ArrowDown: "back", KeyS: "back", |
| ArrowLeft: "turnl", KeyA: "turnl", |
| ArrowRight: "turnr", KeyD: "turnr", |
| }; |
|
|
| |
| |
| const ACTION_KEYS = { |
| KeyB: "spawnBall", |
| KeyC: "chaseToggle", |
| KeyM: "locoToggle", |
| KeyR: "roll", |
| KeyQ: "kickL", |
| KeyE: "kickR", |
| KeyF: "alternateKick", |
| }; |
|
|
| export class KeyboardSource { |
| id = "keyboard"; |
| connected = true; |
| command = new Float32Array(3); |
| axes = { jaw: 0, orbitX: 0, orbitY: 0 }; |
| pressed = { fwd: false, back: false, turnl: false, turnr: false }; |
| onAction = () => {}; |
|
|
| #held = new Set(); |
| #getVelocityLimits; |
| |
| |
| #lims = [NaN, NaN, NaN]; |
| #onKeyDown = null; |
| #onKeyUp = null; |
| #onBlur = null; |
|
|
| constructor({ getVelocityLimits }) { |
| this.#getVelocityLimits = getVelocityLimits; |
| } |
|
|
| init() { |
| this.#onKeyDown = (e) => { |
| if (e.repeat) return; |
| |
| if (e.code === "Space") { |
| e.preventDefault(); |
| this.onAction("reset"); |
| return; |
| } |
| const action = ACTION_KEYS[e.code]; |
| if (action) { |
| this.onAction(action); |
| return; |
| } |
| const move = KEYMAP[e.code]; |
| if (!move) return; |
| e.preventDefault(); |
| this.#held.add(move); |
| this.#refresh(); |
| }; |
| this.#onKeyUp = (e) => { |
| const move = KEYMAP[e.code]; |
| if (!move) return; |
| this.#held.delete(move); |
| this.#refresh(); |
| }; |
| |
| this.#onBlur = () => { |
| this.#held.clear(); |
| this.#refresh(); |
| }; |
| window.addEventListener("keydown", this.#onKeyDown); |
| window.addEventListener("keyup", this.#onKeyUp); |
| window.addEventListener("blur", this.#onBlur); |
| } |
|
|
| dispose() { |
| window.removeEventListener("keydown", this.#onKeyDown); |
| window.removeEventListener("keyup", this.#onKeyUp); |
| window.removeEventListener("blur", this.#onBlur); |
| } |
|
|
| |
| isActive() { |
| return this.#held.size > 0; |
| } |
|
|
| |
| |
| |
| poll() { |
| const [limF, limB, limA] = this.#getVelocityLimits(); |
| if (limF !== this.#lims[0] || limB !== this.#lims[1] || limA !== this.#lims[2]) { |
| this.#refresh(); |
| } |
| } |
|
|
| #refresh() { |
| const lims = this.#getVelocityLimits(); |
| const [limF, limB, limA] = lims; |
| this.#lims = lims; |
| const held = this.#held; |
| this.command[0] = held.has("fwd") ? limF : held.has("back") ? limB : 0; |
| this.command[2] = held.has("turnl") ? limA : held.has("turnr") ? -limA : 0; |
| this.pressed.fwd = held.has("fwd"); |
| this.pressed.back = held.has("back"); |
| this.pressed.turnl = held.has("turnl"); |
| this.pressed.turnr = held.has("turnr"); |
| } |
| } |
|
|