input_handler_input_handler.js

/**
 * @module InputHandler
 * @fileoverview Contains abstract InputHandler class.
 */

import EventHandlerLayer from "../../event/event_handler_layer.js";

/**
 * Abstract input handler. Used for handling input events.
 * @class
 * @abstract
 */
class InputHandler {
    /**
     * Create a new abstract input handler.
     * @param {EventHandler|EventHandlerLayer} parentHandler Parent event handler or layer
     * @param {string} prefix Prefix for event handler
     * @param {function} condition Function for checking whether events should run
     * @constructor
     */
    constructor(parentHandler, prefix, condition = () => { return true; }) {
        this._condition = condition;

        this._parent = parentHandler;
        this._layer = new EventHandlerLayer(this._parent, prefix);

        this._press = new EventHandlerLayer(this._layer, "press/");
        this._release = new EventHandlerLayer(this._layer, "release/");
        this._down = new EventHandlerLayer(this._layer, "down/");

        this._currentlyDown = new Set();
    }

    /**
     * Handle deletion of the handler and its input listeners.
     */
    destructor() {}


    // Getters

    /**
     * Check if the game is in focus (user is not focused on input).
     * @returns {boolean} Whether the game is focused
     */
    gameFocused() {
        const inputs = document.querySelectorAll("input, textarea");
        for (const input of inputs) {
            if (input.matches(":focus"))
                return false;
        }

        return true;
    }

    /**
     * Check if a key is currently being held down.
     * @param {any} key Key to check for
     * @returns {boolean} Whether key is being held down
     */
    isDown(key) {
        return this._currentlyDown.has(key);
    }


    // Key is pressed (fires once)

    /**
     * Add an event to listen for a specific key press. Will fire once.
     * @param {any|any[]} key Key(s) to listen for
     * @param {function} func Function to run upon firing
     */
    onPress(key, func = () => {}) {
        if (key instanceof Array)
            for (const k of key)
                this._press.on(k, func);
        else
            this._press.on(key, func);
    }

    /**
     * Fire a specific key if there are events listening for it.
     * @param {any} key Key to fire
     * @param {any} args Optional arguments to pass into function
     * @protected
     */
    _doPress(key, args = null) {
        if (!this._condition())
            return;

        this._press.do(key, null, args);
    }


    // Key is released (fires once)

    /**
     * Add an event to listen for a specific key release. Will fire once.
     * @param {any|any[]} key Key(s) to listen for
     * @param {function} func Function to run upon firing
     */
    onRelease(key, func = () => {}) {
        if (key instanceof Array)
            for (const k of key)
                this._release.on(k, func);
        else
            this._release.on(key, func);
    }

    /**
     * Fire a specific key if there are events listening for it.
     * @param {any} key Key to fire
     * @param {any} args Optional arguments to pass into function
     * @protected
     */
    _doRelease(key, args = null) {
        if (!this._condition())
            return;

        this._release.do(key, null, args);
    }


    // Key is pressed down (continuously fires)

    /**
     * Add an event to fire while a key is pressed down. Fires continuously.
     * @param {any|any[]} key Key(s) to listen for
     * @param {function} func Function to run upon firing
     */
    whileDown(key, func = () => {}) {
        if (key instanceof Array)
            for (const k of key)
                this._down.on(k, func);
        else
            this._down.on(key, func);
    }

    /**
     * Fire a specific key if there are events listening for it.
     * @param {any} key Key to fire
     * @param {any} args Optional arguments to pass into function
     * @protected
     */
    _doDown(key, args = null) {
        if (!this._condition())
            return;

        this._down.do(key, null, args);
    }
}

export default InputHandler;