UNPKG

@flyskypie/joypad-ts

Version:

A JavaScript library that lets you connect various gaming controllers to your browser using the Gamepad API.

203 lines (202 loc) 6.59 kB
var O = Object.defineProperty; var L = (t, e, s) => e in t ? O(t, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : t[e] = s; var E = (t, e, s) => (L(t, typeof e != "symbol" ? e + "" : e, s), s); class N { constructor() { E(this, "events", {}); } publish(e, s) { this.events.hasOwnProperty(e) && this.events[e].forEach((n) => n(s)); } subscribe(e, s) { return this.events.hasOwnProperty(e) || (this.events[e] = []), this.events[e].push(s), { unsubscribe: () => { const n = this.events[e].indexOf(s); n !== -1 && this.events[e].splice(n, 1); } }; } } const A = new N(); var o = /* @__PURE__ */ ((t) => (t.CONNECT_NATIVE = "gamepadconnected", t.CONNECT_ALIAS = "connect", t.DISCONNECT_NATIVE = "gamepaddisconnected", t.DISCONNECT_ALIAS = "disconnect", t.BUTTON_PRESS_ALIAS = "button_press", t.BUTTON_RELEASE_ALIAS = "button_release", t.AXIS_MOVEMENT_ALIAS = "axis_move", t))(o || {}); const S = { LEFT: { NAME: "left_stick", AXES: { X: 0, Y: 1 } }, RIGHT: { NAME: "right_stick", AXES: { X: 2, Y: 3 } } }, T = { LEFT: "left", RIGHT: "right", TOP: "top", BOTTOM: "bottom" }, M = { button_0: 0, button_1: 1, button_2: 2, button_3: 3, button_4: 4, button_5: 5, button_6: 6, button_7: 7, button_8: 8, button_9: 9, button_10: 10, button_11: 11, button_12: 12, button_13: 13, button_14: 14, button_15: 15, button_16: 16, button_17: 17 }, b = 0.8, f = (...t) => { console.warn && typeof console.warn == "function" ? console.warn(...t) : console.log(...t); }, w = (t, e) => { let s = []; return Object.keys(e).forEach((n) => { e[n] === t && s.push(n); const i = e[n]; Array.isArray(i) && i.indexOf(t) !== -1 && s.push(n); }), s; }, g = (t) => !!(t && t.type && t.playEffect && typeof t.playEffect == "function"), v = () => !!(window.navigator.getGamepads && typeof window.navigator.getGamepads == "function"); class C { constructor() { E(this, "loopStarted", !1); E(this, "instances", {}); E(this, "buttonEvents", { joypad: [] }); E(this, "settings", { axisMovementThreshold: b }); } remove(e) { return delete this.instances[e]; } on(e, s) { switch (e) { case o.CONNECT_ALIAS: return A.subscribe(o.CONNECT_ALIAS, s); case o.DISCONNECT_ALIAS: return A.subscribe(o.DISCONNECT_ALIAS, s); case o.BUTTON_PRESS_ALIAS: return A.subscribe(o.BUTTON_PRESS_ALIAS, s); case o.BUTTON_RELEASE_ALIAS: return A.subscribe(o.BUTTON_RELEASE_ALIAS, s); case o.AXIS_MOVEMENT_ALIAS: return A.subscribe(o.AXIS_MOVEMENT_ALIAS, s); } } vibrate(e, s) { const { vibrationActuator: n } = e, i = s || this.settings.vibration; if (g(n)) { const { type: r } = n; return n.playEffect(r, i); } else f( "No vibration actuator interface found - https://developer.mozilla.org/en-US/docs/Web/API/GamepadHapticActuator" ); } set(e) { const { axisMovementThreshold: s, vibration: n, customButtonMapping: i } = e; if (s !== void 0) { const r = typeof s == "string" ? parseFloat(s) : s; this.settings.axisMovementThreshold = r; } this.settings.vibration = n, this.settings.customButtonMapping = i; } trigger(e, s) { return A.publish(e, s); } } const l = new C(); class B { constructor() { E(this, "id", null); E(this, "start", () => { const e = window.requestAnimationFrame, { buttonEvents: s } = l; let n = window.navigator.getGamepads(); n = Array.prototype.slice.call(n), n.forEach((i, r) => { i && (s.joypad[r] || (s.joypad[r] = {}), l.instances[r] = i, m(i), y(i)); }), s.joypad.forEach((i) => { i && Object.keys(i).forEach((r) => { P(r, i); }); }), this.id = e(this.start); }); } stop(e) { if (e === null) return; const s = window.cancelAnimationFrame; return s(e); } } const _ = new B(), R = () => { window.addEventListener(o.CONNECT_NATIVE, (t) => { if (A.publish(o.CONNECT_ALIAS, t), !l.loopStarted) return l.loopStarted = !0, _.start(); }), window.addEventListener(o.DISCONNECT_NATIVE, (t) => { if (A.publish(o.DISCONNECT_ALIAS, t), l.remove(t.gamepad.index), l.buttonEvents.joypad[t.gamepad.index] = null, !Object.keys(l.instances).length) return l.loopStarted = !1, _.stop(_.id); }), window.addEventListener(o.BUTTON_PRESS_ALIAS, (t) => A.publish(o.BUTTON_PRESS_ALIAS, t)), window.addEventListener(o.BUTTON_RELEASE_ALIAS, (t) => A.publish(o.BUTTON_RELEASE_ALIAS, t)), window.addEventListener(o.AXIS_MOVEMENT_ALIAS, (t) => A.publish(o.AXIS_MOVEMENT_ALIAS, t)); }, m = (t) => { t.buttons.forEach((e, s) => { const { customButtonMapping: n } = l.settings, r = w(s, n || M), { buttonEvents: d } = l; r && r.length && r.forEach((a) => { const c = d.joypad[t.index]; c && (e.pressed ? (c[a] || (c[a] = { pressed: !0, hold: !1, released: !1 }), c[a].button = e, c[a].index = s, c[a].gamepad = t) : !e.pressed && c[a] && (c[a].released = !0, c[a].hold = !1)); }); }); }, y = (t) => { const e = (d) => new CustomEvent(o.AXIS_MOVEMENT_ALIAS, { detail: d }), { axisMovementThreshold: s } = l.settings, { axes: n } = t, r = n.length / 2; n.forEach((d, a) => { if (s && Math.abs(d) > s) { let c = null, p = T.BOTTOM, h = d; a < r ? c = S.LEFT.NAME : c = S.RIGHT.NAME, (a === S.LEFT.AXES.X || a === S.RIGHT.AXES.X) && (p = d < 0 ? T.LEFT : T.RIGHT), (a === S.LEFT.AXES.Y || a === S.RIGHT.AXES.Y) && (p = d < 0 ? T.TOP : T.BOTTOM); const I = { gamepad: t, totalSticks: r, stickMoved: c, directionOfMovement: p, axisMovementValue: h, axis: a }; return window.dispatchEvent(e(I)); } }); }, u = (t, e, s) => { const n = (a) => new CustomEvent(t, { detail: a }), { index: i, gamepad: r } = e[s], d = { buttonName: s, button: e[s].button, index: i, gamepad: r }; window.dispatchEvent(n(d)); }, P = (t, e) => { e[t].pressed ? (u(o.BUTTON_PRESS_ALIAS, e, t), e[t].pressed = !1, e[t].hold = !0, e[t].last_event = o.BUTTON_PRESS_ALIAS) : e[t].hold || e[t].released && e[t].last_event === o.BUTTON_PRESS_ALIAS && (u( o.BUTTON_RELEASE_ALIAS, e, t ), delete e[t]); }; R(); v() || f( "Your browser does not support the Gamepad API - https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API" ); export { l as default };