Skip to content

Instantly share code, notes, and snippets.

@iahuang
Created July 2, 2021 04:56
Show Gist options
  • Save iahuang/50df8a2edde2408e6e54349aefa38ae0 to your computer and use it in GitHub Desktop.
Save iahuang/50df8a2edde2408e6e54349aefa38ae0 to your computer and use it in GitHub Desktop.
A general purpose input listener designed for web-based games.
/*
A general purpose keyboard/mouse input listener designed for
web-based games.
Usage:
let inputManager = new InputManager(window);
let keys = inputManager.pollKeys();
let mouse = inputManager.pollMouse();
if (mouse.get("mouseLeft").down) {
// called the first time that the mouse button is pressed
console.log("hi");
}
*/
class InputState {
down = false;
held = false;
up = false;
}
class InputMap {
inputStates: { [key: string]: InputState } = {};
get(inputName: string): InputState {
if (this.inputStates[inputName] == undefined) {
this.inputStates[inputName] = new InputState();
}
return this.inputStates[inputName];
}
clone(): InputMap {
const clone = new InputMap();
for (const key in this.inputStates) {
const state = this.inputStates[key];
const cloneState = new InputState();
cloneState.down = state.down;
cloneState.held = state.held;
cloneState.up = state.up;
clone.inputStates[key] = cloneState;
}
return clone;
}
}
export default class InputManager {
eventTarget: EventTarget;
keysPressed = new InputMap();
mouseButtons = new InputMap();
mousePosition: { x: number; y: number } = { x: 0, y: 0 };
mouseButtonNames: { [key: number]: string } = {
0: "mouseLeft",
1: "mouseMiddle",
2: "mouseRight",
};
constructor(attachTo: EventTarget) {
this.eventTarget = attachTo;
this.eventTarget.addEventListener("keydown", this.onKeyDown.bind(this));
this.eventTarget.addEventListener("keyup", this.onKeyUp.bind(this));
this.eventTarget.addEventListener("mousedown", this.onMouseDown.bind(this));
this.eventTarget.addEventListener("mouseup", this.onMouseUp.bind(this));
this.eventTarget.addEventListener("mousemove", (ev) => {
let mevt = ev as MouseEvent;
this.mousePosition = {
x: mevt.clientX,
y: mevt.clientY,
};
});
}
onKeyDown(event: Event) {
const state = this.keysPressed.get((event as KeyboardEvent).key);
state.down = true;
state.held = true;
}
onKeyUp(event: Event) {
const state = this.keysPressed.get((event as KeyboardEvent).key);
state.down = false;
state.held = false;
state.up = true;
}
onMouseDown(event: Event) {
const state = this.mouseButtons.get(this.mouseButtonNames[(event as MouseEvent).button]);
state.down = true;
state.held = true;
}
onMouseUp(event: Event) {
const state = this.mouseButtons.get(this.mouseButtonNames[(event as MouseEvent).button]);
state.down = false;
state.held = false;
state.up = true;
}
_poll(inputMap: InputMap): InputMap {
// Read and update input states
const clone = inputMap.clone();
for (const key in inputMap.inputStates) {
const state = inputMap.get(key);
// Make sure the "down" state is only active for one poll call
if (state.down) {
state.down = false;
}
if (state.up) {
state.up = false;
}
}
return clone;
}
pollKeys(): InputMap {
return this._poll(this.keysPressed);
}
pollMouse(): InputMap {
return this._poll(this.mouseButtons);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment