dualsense-ts
Version:
The natural interface for your DualSense and DualSense Access controllers, with Typescript
206 lines • 7.69 kB
JavaScript
"use strict";
var _a, _b, _c, _d, _e, _f;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Input = exports.InputIcon = exports.InputName = exports.InputSet = exports.InputSetComparator = exports.InputId = void 0;
const id_1 = require("./id");
const comparators_1 = require("./comparators");
var id_2 = require("./id");
Object.defineProperty(exports, "InputId", { enumerable: true, get: function () { return id_2.InputId; } });
/** Symbol for modifying the comparison function used by Inputs */
exports.InputSetComparator = Symbol("InputSetComparator");
/** Symbol for modifying the current value of an Input */
exports.InputSet = Symbol("InputSet");
/** Symbol for accessing the name of an Input */
exports.InputName = Symbol("InputName");
/** Symbole for accessing the icon of an Input */
exports.InputIcon = Symbol("InputIcon");
/** Symbol for accessing an Input's event subscriber callbacks */
const InputOns = Symbol("InputOns");
/** Symbol for accessing an Input's single-time subscriber callbacks */
const InputOnces = Symbol("InputOnces");
/** Symbol for notifying an Input that it has a parent */
const InputAdopt = Symbol("InputAdopt");
/** Symbol for accessing an Input's parent Inputs */
const InputParents = Symbol("InputParents");
/** Symbol for accessing the comparison function used by an Input */
const InputComparator = Symbol("InputComparator");
/**
* Input manages the state of a single device input,
* a virtual input, or a group of Input children.
*/
class Input {
constructor(params = {}) {
this.id = id_1.InputId.Unknown;
/** For numeric inputs, ignore state changes smaller than this threshold */
this.threshold = 0;
/** For numeric inputs, ignore states smaller than this deadzone */
this.deadzone = 0;
/** Stores event listeners */
this[_a] = new Map();
/** Stores callbacks waiting for one-time events */
this[_b] = new Map();
/** Returns true if the provided state is worth an event */
this[_c] = comparators_1.BasicComparator;
/** The name of this input */
this[_d] = "Unknown Input";
/** A short name for this input */
this[_e] = "???";
/** Other Inputs that contain this one */
this[_f] = new Set();
const { name, icon, threshold, deadzone } = params;
if (name)
this[exports.InputName] = name;
if (icon)
this[exports.InputIcon] = icon;
if (threshold)
this.threshold = threshold;
if (deadzone)
this.deadzone = deadzone;
setTimeout(() => {
this[exports.InputSetComparator]();
Object.values(this).forEach((value) => {
if (value === this)
return;
if (value instanceof Input)
value[InputAdopt](this);
});
});
}
/** Register a callback to recieve state updates from this Input */
on(event, listener) {
const listeners = this[InputOns].get(event);
if (!listeners) {
this[InputOns].set(event, []);
return this.on(event, listener);
}
listeners.push(listener);
return this;
}
/** Remove a specific callback registered with `on` */
off(event, listener) {
const listeners = this[InputOns].get(event);
if (listeners) {
const idx = listeners.indexOf(listener);
if (idx !== -1)
listeners.splice(idx, 1);
}
return this;
}
/** Alias for `off` */
removeListener(event, listener) {
return this.off(event, listener);
}
/** Remove all listeners for a given event, or all events if none specified */
removeAllListeners(event) {
if (event) {
this[InputOns].set(event, []);
}
else {
this[InputOns] = new Map();
}
return this;
}
/** Register a callback to recieve the next specified update */
once(event, listener) {
const listeners = this[InputOnces].get(event);
if (!listeners) {
this[InputOnces].set(event, []);
return this.once(event, listener);
}
listeners.push(listener);
return this;
}
/** Notify listeners and parents of a state change */
emit(event, changed) {
const listeners = this[InputOns].get(event) ?? [];
listeners.forEach((callback) => {
callback(this, changed);
});
if (event !== "input") {
this.emitOnce(event, changed);
this[InputParents].forEach((input) => {
input.emit(event, changed);
});
}
}
/** Notify one-time listeners of a state change */
emitOnce(event, changed = this) {
const listeners = this[InputOnces].get(event) ?? [];
this[InputOnces].set(event, []);
listeners.forEach((callback) => {
callback(this, changed);
});
}
/** Register a callback to recieve state updates from this Input */
addEventListener(event, listener, { once } = { once: false }) {
if (once) {
if (event === "input") {
throw new Error("Can't listen once to `input` events");
}
return this.once(event, listener);
}
return this.on(event, listener);
}
/** Resolves on the next change to this input's state */
next(type = "change") {
return new Promise((resolve) => {
this.once(type, () => {
resolve({ value: this, done: false });
});
});
}
/** Resolves on the next change to this input's state */
promise(type = "change") {
return new Promise((resolve) => {
this.once(type, () => resolve(this));
});
}
/** Render a debugging string */
toString() {
return `${this[exports.InputIcon]} [${this.active ? "X" : "_"}]`;
}
[(_a = InputOns, _b = InputOnces, _c = InputComparator, Symbol.asyncIterator)]() {
return this;
}
[Symbol.toPrimitive](hint) {
if (hint === "string")
return String(this.state);
if (typeof this.state === "number")
return this.state;
return Number(this.state);
}
get [Symbol.toStringTag]() {
return this.toString();
}
/** Links Inputs to bubble up events */
[(_d = exports.InputName, _e = exports.InputIcon, _f = InputParents, InputAdopt)](parent) {
this[InputParents].add(parent);
}
/** Sets a default comparison type for the Input */
[exports.InputSetComparator]() {
if (typeof this.state === "number") {
this[InputComparator] = comparators_1.ThresholdComparator.bind(this, this.threshold, this.deadzone);
}
else if (this.state instanceof Input) {
this[InputComparator] = comparators_1.VirtualComparator;
}
else {
this[InputComparator] = comparators_1.BasicComparator;
}
}
/** Update the input's state and trigger all necessary callbacks */
[exports.InputSet](state) {
if (this[InputComparator](this.state, state)) {
this.state = state;
this.emit("change", this);
if (typeof state === "boolean")
this.emit(state ? "press" : "release", this);
}
const inputListeners = this[InputOns].get("input");
if (inputListeners !== undefined && inputListeners.length > 0) {
this.emit("input", this);
}
}
}
exports.Input = Input;
//# sourceMappingURL=input.js.map