three-gamepad-controls 0.10.5 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonPressed, getGamepadButtonValue } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonPressed, getGamepadButtonValue } from "./utils.js";
4
4
  import { Vector2, Vector3 } from "three";
5
5
  //#region src/gamepad-arcball-controls.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { getFirstConnectedGamepad, getGamepadByIndex } from "./utils.js";
1
+ import { GamepadManager } from "./gamepad-manager.js";
2
2
  import { EventDispatcher } from "three";
3
3
  //#region src/gamepad-controls.ts
4
4
  /**
@@ -17,10 +17,12 @@ var GamepadControls = class extends EventDispatcher {
17
17
  * The currently active gamepad, or `null` if no gamepad is connected.
18
18
  */
19
19
  gamepad = null;
20
+ #manager;
20
21
  #onGamepadConnected;
21
22
  #onGamepadDisconnected;
22
23
  constructor() {
23
24
  super();
25
+ this.#manager = new GamepadManager();
24
26
  this.#onGamepadConnected = (event) => {
25
27
  this.onGamepadConnected(event.gamepad);
26
28
  };
@@ -37,17 +39,20 @@ var GamepadControls = class extends EventDispatcher {
37
39
  */
38
40
  update(deltaTime) {
39
41
  if (!this.enabled) return;
40
- if (this.gamepad === null) {
41
- const connectedGamepad = getFirstConnectedGamepad();
42
- if (connectedGamepad !== null) this.onGamepadConnected(connectedGamepad);
42
+ this.#manager.activeGamepad = this.gamepad;
43
+ const { gamepad, connected, disconnected } = this.#manager.update();
44
+ if (connected !== null) {
45
+ this.#manager.activeGamepad = this.gamepad;
46
+ this.onGamepadConnected(connected);
47
+ this.#manager.activeGamepad = this.gamepad;
48
+ } else if (disconnected !== null) {
49
+ this.#manager.activeGamepad = this.gamepad;
50
+ this.onGamepadDisconnected(disconnected);
51
+ this.#manager.activeGamepad = this.gamepad;
52
+ return;
43
53
  } else {
44
- const previousGamepad = this.gamepad;
45
- const nextGamepad = getGamepadByIndex(previousGamepad.index);
46
- if (nextGamepad === null) {
47
- this.onGamepadDisconnected(previousGamepad);
48
- return;
49
- }
50
- this.gamepad = nextGamepad;
54
+ this.gamepad = gamepad;
55
+ this.#manager.activeGamepad = this.gamepad;
51
56
  }
52
57
  if (this.gamepad === null) return;
53
58
  this.onUpdate(deltaTime, this.gamepad);
@@ -59,6 +64,7 @@ var GamepadControls = class extends EventDispatcher {
59
64
  window.removeEventListener("gamepadconnected", this.#onGamepadConnected);
60
65
  window.removeEventListener("gamepaddisconnected", this.#onGamepadDisconnected);
61
66
  this.gamepad = null;
67
+ this.#manager.activeGamepad = null;
62
68
  this.enabled = false;
63
69
  }
64
70
  /**
@@ -70,11 +76,14 @@ var GamepadControls = class extends EventDispatcher {
70
76
  * @param gamepad - The gamepad that just connected.
71
77
  */
72
78
  onGamepadConnected(gamepad) {
73
- if (this.gamepad !== null) return;
74
- this.gamepad = gamepad;
79
+ this.#manager.activeGamepad = this.gamepad;
80
+ if (!this.#manager.connect(gamepad)) return;
81
+ const connectedGamepad = this.#manager.activeGamepad;
82
+ if (connectedGamepad === null) return;
83
+ this.gamepad = connectedGamepad;
75
84
  this.dispatchEvent({
76
85
  type: "connected",
77
- gamepad
86
+ gamepad: connectedGamepad
78
87
  });
79
88
  }
80
89
  /**
@@ -86,12 +95,13 @@ var GamepadControls = class extends EventDispatcher {
86
95
  * @param gamepad - The gamepad that just disconnected.
87
96
  */
88
97
  onGamepadDisconnected(gamepad) {
89
- if (this.gamepad?.index !== gamepad.index) return;
90
- const disconnected = this.gamepad;
91
- this.gamepad = null;
98
+ this.#manager.activeGamepad = this.gamepad;
99
+ const disconnectedGamepad = this.#manager.disconnect(gamepad);
100
+ if (disconnectedGamepad === null) return;
101
+ this.gamepad = this.#manager.activeGamepad;
92
102
  this.dispatchEvent({
93
103
  type: "disconnected",
94
- gamepad: disconnected
104
+ gamepad: disconnectedGamepad
95
105
  });
96
106
  }
97
107
  };
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonPressed } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonPressed } from "./utils.js";
4
4
  import { Matrix4, Vector2, Vector3 } from "three";
5
5
  //#region src/gamepad-drag-controls.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonValue } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonValue } from "./utils.js";
4
4
  import { MathUtils, Spherical, Vector3 } from "three";
5
5
  //#region src/gamepad-first-person-controls.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonPressed, getGamepadButtonValue } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonPressed, getGamepadButtonValue } from "./utils.js";
4
4
  import { Quaternion } from "three";
5
5
  //#region src/gamepad-fly-controls.ts
6
6
  /**
@@ -0,0 +1,104 @@
1
+ //#region src/gamepad-manager.ts
2
+ const EMPTY_UPDATE_RESULT = {
3
+ gamepad: null,
4
+ connected: null,
5
+ disconnected: null
6
+ };
7
+ /**
8
+ * Internal input core that owns active gamepad polling and snapshot refresh.
9
+ *
10
+ * This class intentionally tracks only one active gamepad. Higher-level
11
+ * multi-gamepad selection should be built on top of this lifecycle in a
12
+ * later phase.
13
+ *
14
+ * @internal
15
+ */
16
+ var GamepadManager = class {
17
+ /**
18
+ * The active gamepad snapshot, or `null` when none is active.
19
+ */
20
+ activeGamepad = null;
21
+ /**
22
+ * Accepts a gamepad as active when no active gamepad exists.
23
+ *
24
+ * Additional connected gamepads are ignored so the current controls keep
25
+ * using the first active device by default.
26
+ *
27
+ * @param gamepad - Gamepad snapshot to activate.
28
+ * @returns `true` when the gamepad became active, otherwise `false`.
29
+ */
30
+ connect(gamepad) {
31
+ if (this.activeGamepad !== null || !gamepad.connected) return false;
32
+ this.activeGamepad = gamepad;
33
+ return true;
34
+ }
35
+ /**
36
+ * Clears the active gamepad when it matches the disconnecting gamepad index.
37
+ *
38
+ * @param gamepad - Gamepad snapshot that disconnected.
39
+ * @returns The previously active gamepad when it was cleared, otherwise `null`.
40
+ */
41
+ disconnect(gamepad) {
42
+ if (this.activeGamepad?.index !== gamepad.index) return null;
43
+ const disconnectedGamepad = this.activeGamepad;
44
+ this.activeGamepad = null;
45
+ return disconnectedGamepad;
46
+ }
47
+ /**
48
+ * Polls the Gamepad API and refreshes the active gamepad snapshot.
49
+ *
50
+ * The browser exposes gamepad state as snapshots, so polling must replace
51
+ * the stored reference before controls read axes or buttons.
52
+ *
53
+ * @returns The active gamepad and any connect/disconnect transition found.
54
+ */
55
+ update() {
56
+ if (this.activeGamepad === null) {
57
+ const connectedGamepad = this.#getFirstConnectedGamepad();
58
+ if (connectedGamepad === null) return EMPTY_UPDATE_RESULT;
59
+ this.activeGamepad = connectedGamepad;
60
+ return {
61
+ gamepad: connectedGamepad,
62
+ connected: connectedGamepad,
63
+ disconnected: null
64
+ };
65
+ }
66
+ const previousGamepad = this.activeGamepad;
67
+ const nextGamepad = this.#getGamepadByIndex(previousGamepad.index);
68
+ if (nextGamepad === null) {
69
+ this.activeGamepad = null;
70
+ return {
71
+ gamepad: null,
72
+ connected: null,
73
+ disconnected: previousGamepad
74
+ };
75
+ }
76
+ this.activeGamepad = nextGamepad;
77
+ return {
78
+ gamepad: nextGamepad,
79
+ connected: null,
80
+ disconnected: null
81
+ };
82
+ }
83
+ /**
84
+ * Reads the latest connected gamepad snapshot at a known index.
85
+ *
86
+ * @param index - Browser-assigned gamepad index to refresh.
87
+ * @returns A connected gamepad snapshot, or `null` if it is gone.
88
+ */
89
+ #getGamepadByIndex(index) {
90
+ const gamepad = navigator.getGamepads()[index] ?? null;
91
+ return gamepad?.connected === true ? gamepad : null;
92
+ }
93
+ /**
94
+ * Finds the first currently connected gamepad snapshot.
95
+ *
96
+ * @returns The first connected gamepad snapshot, or `null` if none exist.
97
+ */
98
+ #getFirstConnectedGamepad() {
99
+ for (const gamepad of navigator.getGamepads()) if (gamepad?.connected === true) return gamepad;
100
+ return null;
101
+ }
102
+ };
103
+ //#endregion
104
+ export { GamepadManager };
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonValue } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonValue } from "./utils.js";
4
4
  //#region src/gamepad-orbit-controls.ts
5
5
  /**
6
6
  * Default options merged in the constructor when no explicit configuration is provided.
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS } from "./core.js";
2
- import { applyGamepadDeadzone } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone } from "./utils.js";
4
4
  import { Euler } from "three";
5
5
  //#region src/gamepad-pointer-lock-controls.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonValue } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonValue } from "./utils.js";
4
4
  //#region src/gamepad-trackball-controls.ts
5
5
  /**
6
6
  * Default options merged in the constructor when no explicit configuration is provided.
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
- import { applyGamepadDeadzone, getGamepadButtonPressed } from "./utils.js";
3
2
  import { GamepadControls } from "./gamepad-controls.js";
3
+ import { applyGamepadDeadzone, getGamepadButtonPressed } from "./utils.js";
4
4
  import { Matrix4, Quaternion, Vector2, Vector3 } from "three";
5
5
  //#region src/gamepad-transform-controls.ts
6
6
  /**
package/dist/utils.js CHANGED
@@ -37,24 +37,5 @@ const getGamepadButtonValue = (gamepad, button) => {
37
37
  if (gamepadButton.value !== 0) return gamepadButton.value;
38
38
  return gamepadButton.pressed ? 1 : 0;
39
39
  };
40
- /**
41
- * Returns a fresh connected gamepad snapshot by index.
42
- *
43
- * @param index - Gamepad index to look up.
44
- * @returns The connected gamepad snapshot at the index, or `null` when unavailable.
45
- */
46
- const getGamepadByIndex = (index) => {
47
- const gamepad = navigator.getGamepads()[index] ?? null;
48
- return gamepad?.connected === true ? gamepad : null;
49
- };
50
- /**
51
- * Returns the first currently connected gamepad snapshot.
52
- *
53
- * @returns The first connected gamepad snapshot, or `null` when none are connected.
54
- */
55
- const getFirstConnectedGamepad = () => {
56
- for (const gamepad of navigator.getGamepads()) if (gamepad?.connected === true) return gamepad;
57
- return null;
58
- };
59
40
  //#endregion
60
- export { applyGamepadDeadzone, getFirstConnectedGamepad, getGamepadButtonPressed, getGamepadButtonValue, getGamepadByIndex };
41
+ export { applyGamepadDeadzone, getGamepadButtonPressed, getGamepadButtonValue };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "three-gamepad-controls",
3
3
  "description": "Gamepad support for Three.js controls.",
4
- "version": "0.10.5",
4
+ "version": "0.10.6",
5
5
  "homepage": "https://github.com/luckasnix/three-gamepad-controls#readme",
6
6
  "author": {
7
7
  "name": "Kasnix",