UNPKG

keyhawk

Version:

Create keybinds easily with single and multi key support

1,533 lines (1,304 loc) 36.3 kB
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * Contains a list of keys that can be used to create keybinds. */ var Key = { ESC: 'escape', F1: 'f1', F2: 'f2', F3: 'f3', F4: 'f4', F5: 'f5', F6: 'f6', F7: 'f7', F8: 'f8', F9: 'f9', F10: 'f10', F11: 'f11', F12: 'f12', SCROLL_LOCK: 'scrolllock', PAUSE: 'pause', TILDE: '`', ONE: '1', EXCLAMATION_POINT: '!', EXCLAMATION_MARK: '!', TWO: '2', AT: '@', THREE: '3', POUND: '#', NUMBER_SIGN: '#', HASH: '#', FOUR: '4', DOLLAR_SIGN: '$', FIVE: '5', PERCENT: '%', SIX: '6', CARET: '^', SEVEN: '7', AMPERSAND: '&', AND: '&', EIGHT: '8', ASTERISK: '*', MULTIPLY: '*', MULTIPLICATION: '*', NINE: '9', LEFT_PARENTHESES: '(', LEFT_ROUND_BRACKET: '(', ZERO: '0', RIGHT_PARENTHESES: ')', RIGHT_ROUND_BRACKET: ')', DASH: '-', MINUS: '-', SUBTRACT: '-', SUBTRACTION: '-', UNDERSCORE: '_', EQUALS: '=', EQUAL: '=', PLUS: '+', ADD: '+', ADDITION: '+', BACKSPACE: 'backspace', TAB: 'tab', CAPS_LOCK: 'capslock', SPACE: ' ', ENTER: 'enter', CTX: 'contextmenu', CONTEXT: 'contextmenu', CONTEXT_MENU: 'contextmenu', LEFT_BRACKET: '[', LEFT_SQUARE_BRACKET: '[', LEFT_BRACE: '{', RIGHT_BRACKET: ']', RIGHT_SQUARE_BRACKET: ']', RIGHT_BRACE: '}', BACK_SLASH: '\\', VERTICAL_SLASH: '|', UPRIGHT_SLASH: '|', SEMICOLON: ';', COLON: ':', SINGLE_QUOTATION_MARK: "'", DOUBLE_QUOATION_MARK: '"', COMMA: ',', LESS_THAN: '<', LEFT_ANGLE_BRACKET: '<', PERIOD: '.', DOT: '.', GREATER_THAN: '>', RIGHT_ANGLE_BRACKET: '>', FORWARD_SLASH: '/', DIVIDE: '/', DIVISION: '/', QUESTION_MARK: '?', INSERT: 'insert', HOME: 'home', PAGE_UP: 'pageup', DELETE: 'delete', END: 'end', PAGE_DOWN: 'pagedown', ARROW_UP: 'arrowup', ARROW_LEFT: 'arrowleft', ARROW_DOWN: 'arrowdown', ARROW_RIGHT: 'arrowright', NUM_LOCK: 'numlock', ALT: 'alt', META: 'meta', CTRL: 'control', SHIFT: 'shift', A: 'a', B: 'b', C: 'c', D: 'd', E: 'e', F: 'f', G: 'g', H: 'h', I: 'i', J: 'j', K: 'k', L: 'l', M: 'm', N: 'n', O: 'o', P: 'p', Q: 'q', R: 'r', S: 's', T: 't', U: 'u', V: 'v', W: 'w', X: 'x', Y: 'y', Z: 'z' }; /** * A keybind represents one key or a combination of keys that perform an action. * * Keybinds can have an optional callback that is run during the `check` method either automatically * or in your own game loop. * * Keybinds can also have a delay to ensure that a certain amount of time has passed between presses. */ var Keybind = /*#__PURE__*/ function () { /** * The keys that are assigned to this keybind. * * @private * * @property {KeybindObject} */ /** * The callback method to run when this keybind is used. * * @private * * @property {Function} * * @default this.noop */ /** * A delay to set between uses of this keybind in case it shouldn't * be able to be spammed. * * @property {number} * * @default 0 */ /** * A delay to be set before the keybind can even be used at all. * * @property {number} * * @default 0 */ /** * The last time that this keybind was used. * * @property {number} * * @default 0 */ /** * @param {KeybindObject} keys The keys to bind to this keybind. */ function Keybind(keys) { _classCallCheck(this, Keybind); _defineProperty(this, "_keys", void 0); _defineProperty(this, "_action", this._noop); _defineProperty(this, "_delay", 0); _defineProperty(this, "_initialDelay", 0); _defineProperty(this, "_lastUsed", 0); this._keys = keys; } /** * Gets the keys that are a part of this keybind. * * @returns {KeybindObject} */ _createClass(Keybind, [{ key: "delay", /** * Sets the delay between keybind uses. * * @param {number} ms The time in milliseconds to delay use. * * @returns {Keybind} Returns this for chaining. */ value: function delay(ms) { this._delay = ms; this._lastUsed = -this._delay + 1; return this; } /** * Sets the initial delay before the keybind can be used for the first time. * * @param {number} ms The time in milliseconds before the keybind can be used. * * @returns {Keybind} Retursn this for chaining. */ }, { key: "initialDelay", value: function initialDelay(ms) { this._initialDelay = ms; return this; } /** * Sets the callback method sthat will be run when this keybind is active. * * @param {Function} fn The callback method to use. * * @returns {Keybind} Returns this for chaining. */ }, { key: "action", value: function action(fn) { this._action = fn; return this; } /** * Run the action associated with this keybind. * * @param {number} time The time that the keybind was used. */ }, { key: "run", value: function run(time) { this._action(); this._lastUsed = time; } /** * An empty method to use as the default action for the keybind in case no action is added. * * @private */ }, { key: "_noop", value: function _noop() {} }, { key: "keys", get: function get() { return this._keys; } /** * Gets the last time that this keybind was used. * * @returns {number} */ }, { key: "lastUsed", get: function get() { return this._lastUsed; } }]); return Keybind; }(); var Options = /** * By default Keyhawk will use the Deltaframe module to handle the checking of keybind uses. * * If you would like to use your own game loop or even just rather use a simple debounce method, * you can set this to false. * * @property {boolean} * * @default true */ /** * @param {Object} options The initialization options passed to Keyhawk. */ function Options(options) { _classCallCheck(this, Options); _defineProperty(this, "useLoop", true); Object.assign(this, options); }; function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties$1(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass$1(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties$1(Constructor.prototype, protoProps); if (staticProps) _defineProperties$1(Constructor, staticProps); return Constructor; } function _defineProperty$1(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var Options$1 = /*#__PURE__*/ function () { /** * The lowest the fps can drop to before the Deltaframe restarts to attempt to fix the problem. * * @property {number} * * @default 15 */ /** * The fps that the game loop should aim to achieve. * * @property {number} * * @default 60 */ /** * When the fps goes below the minFps Deltaframe will restart. This indicates how many times it will restart before stopping permanently. * * @property {number} * * @default Infinity */ /** * Specify the amount of milliseconds that Deltaframe should run for. * * @property {number} * * @default Infinity */ /** * Indicates whether setTimeout should be used even if requestAnimationFrame is supported by the user's browser. * * @property {number} * * @default false */ /** * @param {Object} options The initialization options passed to Deltaframe. */ function Options() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck$1(this, Options); _defineProperty$1(this, "minFps", 15); _defineProperty$1(this, "targetFps", 60); _defineProperty$1(this, "maxRestartAttempts", Infinity); _defineProperty$1(this, "runTime", Infinity); _defineProperty$1(this, "forceSetTimeout", false); Object.assign(this, options); } /** * Return the minFps as a decimal representing the amount of time before a frame should occur. * * @returns {number} */ _createClass$1(Options, [{ key: "minFpsCalc", get: function get() { return Math.floor(1000 / this.minFps); } /** * Return the targetFps as a decimal representing the amount of time before a frame should occur. * * @returns {number} */ }, { key: "targetFpsCalc", get: function get() { return Math.floor(1000 / this.targetFps); } }]); return Options; }(); var TaskOptions = /** * Specifies the time in between runs. * * @property {number} * * @default 1000 */ /** * A delay before running the task for the first time. * * @property {number} * * @default 0 */ /** * Specify this to have the task be destroyed after being run the specified amount of times. * * @property {number} * * @default Infinity */ /** * @param {Object} options The options passed when creating a new task. */ function TaskOptions(options) { _classCallCheck$1(this, TaskOptions); _defineProperty$1(this, "interval", 1000); _defineProperty$1(this, "delay", 0); _defineProperty$1(this, "timesToRun", Infinity); Object.assign(this, options); }; /** * Defines a task that can be created and added to the task manager. */ var Task = /*#__PURE__*/ function () { /** * The name of this task. * * @property {string} */ /** * A reference to the function to call when this task is run. * * @property {Function} */ /** * A reference to the options for this task. * * @property {TaskOptions} */ /** * The number of times that this task has been run. * * @property {number} */ /** * The time this task was last run at. * * @property {number} */ /** * @param {string} name The name of this task. * @param {Function} fn The function to call when this task is run. * @param {Object} options The options for this task. */ function Task(name, fn, options) { _classCallCheck$1(this, Task); _defineProperty$1(this, "name", void 0); _defineProperty$1(this, "fn", void 0); _defineProperty$1(this, "options", void 0); _defineProperty$1(this, "timesRun", 0); _defineProperty$1(this, "lastRunAt", 0); this.name = name; this.fn = fn; this.options = new TaskOptions(options); } /** * Runs the function associated with this task. */ _createClass$1(Task, [{ key: "run", value: function run() { this.fn(); this.timesRun++; } }]); return Task; }(); /** * The task manager is used to add and manage tasks that are supposed to run at specific times, on repeat, or a * predetermined number of times. */ var TaskManager = /*#__PURE__*/ function () { function TaskManager() { _classCallCheck$1(this, TaskManager); _defineProperty$1(this, "_active", []); } _createClass$1(TaskManager, [{ key: "addTask", /** * Adds a task to the task manager. * * @param {string} name The name of the task to add. * @param {string} fn The function to call when this task is run. * @param {Object} [options] * @param {number} [options.interval=1000] Specifies the time in between runs. * @param {number} [options.delay=0] A delay before running the task for the first time. * @param {number} [options.timesToRun=Infinity] Specify this to have the task be destroyed after being run the specified amount of times. */ value: function addTask(name, fn) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var task = new Task(name, fn, options); this._active.push(task); } /** * Removes a task by its name. * * @param {string} name The name of the task to remove. */ }, { key: "removeTask", value: function removeTask(name) { this._active = this._active.filter(function (task) { return task.name !== name; }); } /** * Checks to see if any tasks need to be run and runs them if so. * * This will also remove tasks if they are no longer needed. * * @param {number} time The current timestamp. */ }, { key: "update", value: function update(time) { var _this = this; this.active.map(function (task) { if (time > task.options.delay && time - task.lastRunAt >= task.options.interval) { task.run(); task.lastRunAt = time; if (task.timesRun > task.options.timesToRun) _this.removeTask(task.name); } }); } }, { key: "active", /** * Returns all of the active tasks. * * @returns {Array<Tas>} */ get: function get() { return this._active; } }]); return TaskManager; }(); var RequestAnimationFrame = /*#__PURE__*/ function () { /** * A reference to the id returned by requestAnimationFrame or setTimeout so that we can cancel their operation when needed. * * @property {number} */ /** * Keeps track of whether the loop is already running or not so it's not accidently restarted. * * @property {boolean} * * @default false */ /** * The function that should be run on every update of the loop. * * @property {Function} * * @default ()=>{} */ /** * Indicates whether setTImeout is being used instead of requestAnimationFrame. * * @property {boolean} * * @default false */ function RequestAnimationFrame() { _classCallCheck$1(this, RequestAnimationFrame); _defineProperty$1(this, "id", 0); _defineProperty$1(this, "running", false); _defineProperty$1(this, "fn", function () {}); _defineProperty$1(this, "usingSetTimeout", false); /** * Use the version of requestAnimationFrame that is supported by the user's browser and if none are supported, use setTimeout instead. * * @property {RequestAnimationFrame|setTimeout} */ window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || function (f) { return setTimeout(f, 1000 / 60); }; /** * Use the version of cancelAnimationFrame that is supported by the user's browser and if none are supported, then setTimeout was used * and so we use clearTimeout instead. * * @property {cancelAnimationFrame} */ window.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || function () { clearTimeout(this.id); }; } /** * Start the operation of the requestAnimationFrame or setTimeout loop. * * @param {Function} fn The function to run every update of the loop. * @param {boolean} forceSetTimeout Indicates whether setTimeout should be used even if the user's browser supports requestAnimationFrame. */ _createClass$1(RequestAnimationFrame, [{ key: "start", value: function start(fn, forceSetTimeout) { var _this = this; if (this.running) return; this.running = true; this.fn = fn; if (forceSetTimeout) { this.usingSetTimeout = true; this.updateTimeout(); } else { window.requestAnimationFrame(function (time) { return _this.updateRAF(time); }); } } /** * Call requestAnimationFrame recursively so that the loop keeps going and also send the timestamps over to Deltaframe. * * @param {number} timestamp The timestamp from the most recent requestAnimationFrame request. */ }, { key: "updateRAF", value: function updateRAF(timestamp) { var _this2 = this; this.running = true; this.fn(timestamp); this.id = window.requestAnimationFrame(function (time) { return _this2.updateRAF(time); }); } /** * Call setTimeout recursively so that the loop keeps going and also send the timestamps over to Deltaframe. */ }, { key: "updateTimeout", value: function updateTimeout() { var _this3 = this; var timestamp = window.performance.now(); this.fn(timestamp); this.id = window.setTimeout(function () { return _this3.updateTimeout(); }, 1000 / 60); } /** * Restart the requestAnimation or setTimeout loop. */ }, { key: "restart", value: function restart() { var _this4 = this; if (this.usingSetTimeout) window.clearTimeout(this.id);else window.cancelAnimationFrame(this.id); this.id = 0; this.running = false; if (this.usingSetTimeout) this.updateTimeout();else window.requestAnimationFrame(function (time) { return _this4.updateRAF(time); }); this.running = true; } /** * Stop the loop by calling cancelAnimationFrame or clearTimeout. */ }, { key: "stop", value: function stop() { if (this.usingSetTimeout) window.clearTimeout(this.id);else window.cancelAnimationFrame(this.id); this.id = 0; this.running = false; this.fn = function () {}; return; } }]); return RequestAnimationFrame; }(); /** * Deltaframe is an animation and game loop manager that makes sure your application is punctual and performant. */ var Deltaframe = /*#__PURE__*/ function () { /** * A reference to the options for this instance of Deltaframe. * * @private * * @property {Options} */ /** * The amount of times Deltaframe has had to restart due to the average fps dipping below the minimum fps for a * series of frames. * * @private * * @property {number} */ /** * Indicates whether Deltaframe is currently is currently running and not pausedor stopped. * * @private * * @property {boolean} */ /** * Indicates whether Deltaframe is currently paused. * * @private * * @property {boolean} */ /** * The function that will be called on every Deltaframe update. * * @private * * @property {Function} */ /** * The current frame that Deltaframe is on. * * @private * * @property {number} */ /** * The current timestamp as of the latest call to RequestAnimationFrame. * * @private * * @property {DOMHighResTimeStamp|number} */ /** * The timestamp before the current timestamp. * * @private * * @property {DOMHighResTimeStamp|number} */ /** * The difference in time between the current time and the last time. * * @private * * @property {number} */ /** * The average difference in time between frames. * * @private * * @property {number} */ /** * A set of up to 10 recent previous delta values that are used to get the mean delta. * * @private * * @property {Array<number>} */ /** * Since we only want to go up to 10 on the deltaHistory, we keep track of what index we're on so we can reset to 0 once were at 10. * * @private * * @property {number} */ /** * Initialize the RequestAnimationFrame abstraction module. * * @private * * @property {RequestAnimationFrame} */ /** * Use the version of hidden that's supported by the user's browser. * * @private * * @property {document.hidden} */ /** * A reference to the task manager. * * @private * * @property {TaskManager} */ /** * @param {Object} [options] The options to pass to this Deltaframe instance. * @param {number} [options.minFps=15] The minimum fps value allowed before Deltaframe will restart to try to correct the issue. * @param {number} [options.targetFps=60] The fps that Deltaframe should aim to achieve. * @param {number} [options.maxRestartAttempts=Infinity] The number of times Deltaframe will restart due to problems before stopping entirely. * @param {number} [options.runTime=Infinity] The length of time that this instance of Deltaframe will run. This can be used to create an animation that lasts a specific amount of time. * @param {boolean} [options.forceSetTimeout=false] If set to true, Deltaframe will use setTimeout for the loop instead of requestAnimationFrame. */ function Deltaframe(options) { _classCallCheck$1(this, Deltaframe); _defineProperty$1(this, "_options", void 0); _defineProperty$1(this, "_restartAttempts", void 0); _defineProperty$1(this, "_running", void 0); _defineProperty$1(this, "_paused", void 0); _defineProperty$1(this, "_fn", void 0); _defineProperty$1(this, "_frame", void 0); _defineProperty$1(this, "_time", void 0); _defineProperty$1(this, "_prevTime", void 0); _defineProperty$1(this, "_delta", void 0); _defineProperty$1(this, "_deltaAverage", void 0); _defineProperty$1(this, "_deltaHistory", void 0); _defineProperty$1(this, "_deltaIndex", void 0); _defineProperty$1(this, "_raf", void 0); _defineProperty$1(this, "_hidden", void 0); _defineProperty$1(this, "_tasks", new TaskManager()); this._options = new Options$1(options); this._restartAttempts = 0; this._running = false; this._paused = false; this._fn = function () {}; this._frame = 0; this._time = 0; this._prevTime = 0; this._delta = 0; this._deltaAverage = 0; this._deltaHistory = []; this._deltaIndex = 0; this._raf = new RequestAnimationFrame(); this._hidden = document.hidden; this._boot(); } /** * Return the number of times that Deltafram has restarted. * * @returns {number} */ _createClass$1(Deltaframe, [{ key: "start", /** * Start the loop. * * @param {Function} fn The function to be called every step by the loop. */ value: function start(fn) { var _this = this; this._fn = fn; this._prevTime = 0; this._running = true; this._raf.start(function (timestamp) { return _this._update(timestamp); }, this._options.forceSetTimeout); } /** * Pause the loop operation saving the state to be resumed at a later time. */ }, { key: "pause", value: function pause() { this._paused = true; this._running = false; } /** * Resume the loop from a paused state. */ }, { key: "resume", value: function resume() { this._paused = false; this._prevTime = window.performance.now(); this._running = true; } /** * Stop the loop and reset all time values of Deltaframe. */ }, { key: "stop", value: function stop() { var _this2 = this; this._restartAttempts = 0; this._running = false; this._paused = false; this._fn = function () {}; this._frame = 0; this._time = 0; this._prevTime = 0; this._delta = 0; this._deltaHistory = []; this._deltaIndex = 0; document.removeEventListener('visibilitychange', function () { return _this2._visibilityChange; }); this._raf.stop(); return; } /** * Initialize the page visibility events which will let us save resources by pausing our updates when the user is not * interacting with the page running Deltaframe. * * @private */ }, { key: "_boot", value: function _boot() { var _this3 = this; document.addEventListener("visibilitychange", function () { return _this3._visibilityChange(); }); } /** * Update is called whenever requestAnimationFrame decides it can process the next step of the loop or roughly 60 * times per second using setTimeout. * * @private * * @param {DOMHighResTimeStamp|number} timestamp The timestamp as returned from requestAnimationFrame. */ }, { key: "_update", value: function _update(timestamp) { if (this._paused) return; if (timestamp >= this._options.runTime) { this.stop(); return; } this._time = timestamp; this._delta = timestamp - this._prevTime; if (this._deltaIndex === 10) this._deltaIndex = 0; this._deltaHistory[this._deltaIndex] = this._delta; this._deltaIndex++; var mean = 0; for (var i = 0; i < this._deltaHistory.length; ++i) { mean += this._deltaHistory[i]; } mean /= 10; this._deltaAverage = mean; if (this._deltaAverage >= this._options.minFpsCalc) { if (this._restartAttempts === this._options.maxRestartAttempts) { this.stop(); return; } this._raf.restart(); this._restartAttempts++; } if (this._deltaAverage >= this._options.targetFpsCalc) { this._frame++; this._fn(timestamp, this._delta, this._deltaAverage); if (this._tasks.active.length > 0) this._tasks.update(this.time); this._prevTime = timestamp; } } /** * When the the user has switched to a different tab and is not on the same page that Deltaframe is running on, Deltaframe * will pause and when the user comes back it will resume. * * @private */ }, { key: "_visibilityChange", value: function _visibilityChange() { var visibility = document.visibilityState; if (this.isPaused && visibility === 'visible') this.resume();else if (this.isRunning && visibility === 'hidden') this.pause(); } }, { key: "timesRestarted", get: function get() { return this._restartAttempts; } /** * Returns if Deltaframe is running or not. * * @returns {boolean} */ }, { key: "isRunning", get: function get() { return this._running; } /** * Returns if Deltaframe is paused or not. * * @returns {boolean} */ }, { key: "isPaused", get: function get() { return this._paused; } /** * Returns the current frame. * * @returns {number} */ }, { key: "frame", get: function get() { return this._frame; } /** * Returns the current time. * * @returns {DOMHighResTimeStamp|number} */ }, { key: "time", get: function get() { return this._time; } /** * Returns a reference to the task manager. * * @returns {TaskManager} */ }, { key: "tasks", get: function get() { return this._tasks; } }]); return Deltaframe; }(); /** * Create keybinds easily with single and multi key support */ var Keyhawk = /*#__PURE__*/ function () { /** * The selected options for Keyhawk. * * @property {Options} * * @private */ /** * A list of keys that can be selected to be used in keybinds. * * @private */ /** * A list of the created keybinds. * * @property {Array<Keybind>} * * @private */ /** * If you don't want to create your own game loop to check keykind uses on an interval, you opt in to * use the Deltaframe package. * * @property {Deltaframe|null} * * @private */ /** * Keeps track of what keys have been pressed. * * @private * * @property {Object} */ /** * Indicates whether using keybinds is currently disabled or not. * * @private * * @property {boolean} */ /** * The amount of time that keybinds are disabled for, if any. * * @private * * @property {number} */ /** * @param {Object} [options] * @param {boolean} [options.useLoop=true] By default Keyhawk will use the Deltaframe module to handle the checking of keybind uses. If you would like to use your own game loop or even just rather use a simple debounce method, you can set this to false. */ function Keyhawk() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, Keyhawk); _defineProperty(this, "_options", void 0); _defineProperty(this, "_KEY", Key); _defineProperty(this, "_keybinds", []); _defineProperty(this, "_loop", null); _defineProperty(this, "_pressed", {}); _defineProperty(this, "_disabled", false); _defineProperty(this, "_disabledTime", 0); this._options = new Options(options); this._boot(); } /** * Returns the keys that can be used to create keybinds. * * @returns {Keys} */ _createClass(Keyhawk, [{ key: "_boot", /** * Setup the keydown and keyup event listeners and also initialize Deltaframe if it is being used. * * @private */ value: function _boot() { var _this = this; window.addEventListener('keydown', function (ev) { return _this._keydown(ev); }); window.addEventListener('keyup', function (ev) { return _this._keyup(ev); }); if (this._options.useLoop) { this._loop = new Deltaframe({}); this._loop.start(function (time) { return _this.check(time); }); } } /** * Creates a new keybind with the specified keys. * * @param {...string} keys One or more keys from the `KEYS` property to attach to this keybind. * * @returns {Keybind} Returns the newly created keybind. */ }, { key: "keybind", value: function keybind() { for (var _len = arguments.length, keys = new Array(_len), _key = 0; _key < _len; _key++) { keys[_key] = arguments[_key]; } if (!keys) { console.warn('At least one key must be provided to create a keybind'); return; } var keyObj = {}; for (var _i = 0, _keys = keys; _i < _keys.length; _i++) { var key = _keys[_i]; keyObj[key] = true; } var keybind = new Keybind(keyObj); this._keybinds.push(keybind); return keybind; } /** * Checks to see which key conditions are currently being met and runs the keybind's attached callback method. * * @param {number} time The current timestamp which is used to check for delays and is passed to the keybind's callback method. */ }, { key: "check", value: function check(time) { var _this2 = this; this._keybinds.forEach(function (o) { var isActive = Object.entries(o.keys).every(function (arr) { return _this2._pressed[arr[0]] == arr[1]; }); var isPastInitialDelay = time > o._initialDelay; var isTime = time - o._lastUsed > o._delay; if (_this2._disabled) { if (time < time + _this2._disabledTime) return;else _this2._resetDisabled(); } if (isActive && isPastInitialDelay && isTime) o.run(time); }); } /** * Disables the use of all keybinds until enable is called or until the wait time has expired if it is provided. * * @param {number} [lengthOfTime=Infinity] An optional amount of time to wait until keybinds are automatically enabled again. */ }, { key: "disable", value: function disable() { var lengthOfTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity; this._disabled = true; this._disabledTime = lengthOfTime; } /** * If no end time is passed when calling the `disable` method, this method has to be called to enable the use of * keybinds again. */ }, { key: "enable", value: function enable() { this._resetDisabled(); } /** * When a key is pressed, add it to the `pressed` Object if it doesn't already exist and set it to `true`. * * @private * * @param {KeyboardEvent} event The event generated from the keypress. */ }, { key: "_keydown", value: function _keydown(event) { this._pressed[event.key.toLowerCase()] = true; event.preventDefault(); return; } /** * When a key is released, set its property in the `pressed` object to `false`. * * @private * * @param {KeyboardEvent} event The event generated from the keypress. */ }, { key: "_keyup", value: function _keyup(event) { this._pressed[event.key.toLowerCase()] = false; event.preventDefault(); } /** * Resets both disabled properties, disabled to false and disabled time to 0 when keybinds are enabled * again after being disabled. * * @private */ }, { key: "_resetDisabled", value: function _resetDisabled() { this._disabled = false; this._disabledTime = 0; } }, { key: "KEY", get: function get() { return this._KEY; } /** * Returns whether keybinds are currently disabled or not. * * @returns {boolean} */ }, { key: "disabled", get: function get() { return this._disabled; } /** * Returns the disabled time, if it was set. * * @returns {number} */ }, { key: "disabledTime", get: function get() { return this._disabledTime; } }]); return Keyhawk; }(); export default Keyhawk;