evidently-input
Version:
TypeScript powered for easily handling input in your games.
95 lines (94 loc) • 4.51 kB
TypeScript
/**
* Handles the keyboard events and provides an API for interacting with it easily. The simplest way to use it is:
*
* 1. Create a new instance of `KeyboardInput`.
* 2. Call `registerListeners()` passing the `document`.
* 3. Call `update` **at the end** of every update frame of your game.
* 4. Use the functions of this library in your code.
*
* ### How does it work?
*
* You need to call the `update()` method at the **end** of every frame to properly transition internal state.
* The workflow for this class is as follows:
* 1. Browser receives events from the user and fires the corresponding events.
* 2. `KeyboardInput` receives those events and updates its internal state.
* 3. Update loop for your game runs and you can use the methods in this class to interact.
* 4. At the end of the your game's update loop `update()` is called on this class. (or at any point past when you know you'll interact with this class)
* 5. Repeat
*
* ### Understanding key states
*
* There are three states recognized by this class for a key: down, pressed and released:
*
* * Use `pressed` if you want to know if a key was pressed at least once this frame.
* * Use `released` if you want to knof iw a key was releast at least once this frame.
* * Use `down` if you want to know if a key was either pressed this frame or pressed in any previous frame and not released so far.
*
*
* You may notice that in a situation where during the course of a single frame a key is both pressed and released, all three states
* will report true. That's an intentional design decision to avoid a very uncommon but still possible bug. Imagine this code:
*
* ```
* if (keyboardInput.isKeyDown("a")) {
* this.move({x: -1});
* }
* ```
*
* If for some reason your game runs slow (maybe it naturally has low FPS or it's lagging at the moment), if you pressed and released the `a` key
* during the span of a single frame as a player you'd still expect the move to trigger - sure, you released the key but you also pressed it. The
* code can't use `isKeyPressed` instead, because you want the player to keep moving as long as the key is down. You could work around this by
* expanding the condition to `i.isKeyDown || i.isKeyPressed`, but the issues are:
*
* 1. You probably didn't think about this bug in the first place. Which is fine, it's extremely unlikely to ever be an issue for the vast majority
* of games.
* 2. The expanded condition is less readable.
* 3. The change on its own doesn't break anything, so you lose nothing by having it baked in the system.
*/
export declare class KeyboardInput {
private _keysDown;
private _keysPressed;
private _keysReleased;
private _isCtrlDown;
private _isShiftDown;
private _isAltDown;
private _wasCtrlDownThisFrame;
private _wasShiftDownThisFrame;
private _wasAltDownThisFrame;
private _lastKeyPressed;
get isCtrlDown(): boolean;
get isShiftDown(): boolean;
get isAltDown(): boolean;
get isAnyKeyDown(): boolean;
get isAnyKeyPressed(): boolean;
get isAnyKeyReleased(): boolean;
get lastKeyPressed(): string;
isKeyDown: (key: string) => boolean;
isKeyPressed: (key: string) => boolean;
isKeyReleased: (key: string) => boolean;
constructor();
/**
* Updates the internal state, should be called at the end of each frame.
*/
update: () => void;
/**
* Resets the internal state of this class to what it is during creation (nothing pressed, released or held down)
*/
flush: () => void;
/**
* Registers the `keydown` and `keyup` listeners on the passed element so that the class
* can handle the input.
*
* @param {GlobalEventHandlers} element To avoid issues with focus it's best to pass `document` here
*/
registerListeners(element: GlobalEventHandlers): void;
/**
* Handles a keyboard event updating the internal status. This will be called automatically if you register the listeners
* via `registerListeners`. If you have listeners being registered somewhere else entirely and would like to keep it
* that way, you can manually call this method passing the KeyboardEvent.
*
* @warning This method will call `preventDefault` on the event passed.
*
* @param {KeyboardEvent} event
*/
handleEvent: (event: KeyboardEvent) => void;
}