@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.1.4 → 0.2.1

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.
Files changed (94) hide show
  1. package/.eslintrc.js +1 -1
  2. package/.prettierrc.json +1 -0
  3. package/dist/lib-pixelstreamingfrontend.esm.js +1 -1
  4. package/dist/lib-pixelstreamingfrontend.js +1 -1
  5. package/package.json +6 -5
  6. package/src/AFK/AFKController.ts +10 -32
  7. package/src/Config/Config.ts +179 -201
  8. package/src/Config/SettingBase.ts +61 -2
  9. package/src/Config/SettingFlag.ts +10 -48
  10. package/src/Config/SettingNumber.ts +10 -28
  11. package/src/Config/SettingOption.ts +13 -46
  12. package/src/Config/SettingText.ts +9 -37
  13. package/src/DataChannel/DataChannelController.ts +6 -26
  14. package/src/DataChannel/DataChannelLatencyTestController.ts +38 -33
  15. package/src/DataChannel/DataChannelLatencyTestResults.ts +8 -10
  16. package/src/DataChannel/DataChannelSender.ts +5 -15
  17. package/src/DataChannel/LatencyTestResults.ts +5 -15
  18. package/src/FreezeFrame/FreezeFrame.ts +7 -19
  19. package/src/FreezeFrame/FreezeFrameController.ts +3 -14
  20. package/src/Inputs/GamepadController.ts +123 -221
  21. package/src/Inputs/GamepadTypes.ts +23 -0
  22. package/src/Inputs/IInputController.ts +17 -0
  23. package/src/Inputs/InputClassesFactory.ts +38 -45
  24. package/src/Inputs/KeyCodes.ts +114 -0
  25. package/src/Inputs/KeyboardController.ts +49 -232
  26. package/src/Inputs/MouseController.ts +71 -297
  27. package/src/Inputs/MouseControllerHovering.ts +118 -0
  28. package/src/Inputs/MouseControllerLocked.ts +194 -0
  29. package/src/Inputs/TouchController.ts +49 -105
  30. package/src/Inputs/TouchControllerFake.ts +132 -0
  31. package/src/Inputs/XRGamepadController.ts +35 -44
  32. package/src/PeerConnectionController/AggregatedStats.ts +26 -54
  33. package/src/PeerConnectionController/CandidatePairStats.ts +1 -1
  34. package/src/PeerConnectionController/CandidateStat.ts +1 -1
  35. package/src/PeerConnectionController/PeerConnectionController.ts +177 -162
  36. package/src/PixelStreaming/PixelStreaming.ts +174 -226
  37. package/src/UI/OnScreenKeyboard.ts +14 -9
  38. package/src/UeInstanceMessage/ResponseController.ts +6 -15
  39. package/src/UeInstanceMessage/SendMessageController.ts +16 -18
  40. package/src/UeInstanceMessage/StreamMessageController.ts +3 -12
  41. package/src/UeInstanceMessage/ToStreamerMessagesController.ts +3 -9
  42. package/src/Util/EventEmitter.ts +17 -22
  43. package/src/Util/FileUtil.ts +11 -34
  44. package/src/Util/IURLSearchParams.ts +25 -0
  45. package/src/Util/InputCoordTranslator.ts +73 -0
  46. package/src/Util/RTCUtils.ts +23 -15
  47. package/src/VideoPlayer/StreamController.ts +6 -23
  48. package/src/VideoPlayer/VideoPlayer.ts +9 -30
  49. package/src/WebRtcPlayer/WebRtcPlayerController.ts +328 -690
  50. package/src/WebXR/WebXRController.ts +82 -94
  51. package/src/pixelstreamingfrontend.ts +6 -10
  52. package/types/AFK/AFKController.d.ts +0 -1
  53. package/types/Config/Config.d.ts +6 -5
  54. package/types/Config/SettingBase.d.ts +13 -0
  55. package/types/Config/SettingFlag.d.ts +1 -10
  56. package/types/Config/SettingNumber.d.ts +1 -5
  57. package/types/Config/SettingOption.d.ts +1 -10
  58. package/types/Config/SettingText.d.ts +1 -9
  59. package/types/DataChannel/DataChannelLatencyTestController.d.ts +1 -1
  60. package/types/Inputs/GamepadController.d.ts +22 -46
  61. package/types/Inputs/GamepadTypes.d.ts +7 -0
  62. package/types/Inputs/IInputController.d.ts +16 -0
  63. package/types/Inputs/InputClassesFactory.d.ts +7 -8
  64. package/types/Inputs/KeyCodes.d.ts +5 -0
  65. package/types/Inputs/KeyboardController.d.ts +17 -45
  66. package/types/Inputs/MouseController.d.ts +33 -68
  67. package/types/Inputs/MouseControllerHovering.d.ts +26 -0
  68. package/types/Inputs/MouseControllerLocked.d.ts +31 -0
  69. package/types/Inputs/TouchController.d.ts +19 -44
  70. package/types/Inputs/TouchControllerFake.d.ts +29 -0
  71. package/types/Inputs/XRGamepadController.d.ts +0 -7
  72. package/types/PeerConnectionController/PeerConnectionController.d.ts +4 -1
  73. package/types/PixelStreaming/PixelStreaming.d.ts +14 -2
  74. package/types/UI/OnScreenKeyboard.d.ts +2 -2
  75. package/types/Util/EventEmitter.d.ts +1 -1
  76. package/types/Util/IURLSearchParams.d.ts +9 -0
  77. package/types/Util/InputCoordTranslator.d.ts +29 -0
  78. package/types/VideoPlayer/StreamController.d.ts +0 -2
  79. package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +19 -17
  80. package/types/pixelstreamingfrontend.d.ts +1 -1
  81. package/src/Inputs/FakeTouchController.ts +0 -199
  82. package/src/Inputs/HoveringMouseEvents.ts +0 -192
  83. package/src/Inputs/IMouseEvents.ts +0 -64
  84. package/src/Inputs/ITouchController.ts +0 -29
  85. package/src/Inputs/LockedMouseEvents.ts +0 -287
  86. package/src/Util/CoordinateConverter.ts +0 -290
  87. package/src/Util/EventListenerTracker.ts +0 -29
  88. package/types/Inputs/FakeTouchController.d.ts +0 -61
  89. package/types/Inputs/HoveringMouseEvents.d.ts +0 -56
  90. package/types/Inputs/IMouseEvents.d.ts +0 -53
  91. package/types/Inputs/ITouchController.d.ts +0 -24
  92. package/types/Inputs/LockedMouseEvents.d.ts +0 -80
  93. package/types/Util/CoordinateConverter.d.ts +0 -100
  94. package/types/Util/EventListenerTracker.d.ts +0 -14
@@ -48,15 +48,8 @@ export class LatencyTestResults {
48
48
  * Process the encoder times and set them
49
49
  */
50
50
  processFields() {
51
- if (
52
- this.EncodeMs == null &&
53
- (this.PreEncodeTimeMs != null || this.PostEncodeTimeMs != null)
54
- ) {
55
- Logger.Log(
56
- Logger.GetStackTrace(),
57
- `Setting Encode Ms \n ${this.PostEncodeTimeMs} \n ${this.PreEncodeTimeMs}`,
58
- 6
59
- );
51
+ if (this.EncodeMs == null && (this.PreEncodeTimeMs != null || this.PostEncodeTimeMs != null)) {
52
+ Logger.Info(`Setting Encode Ms \n ${this.PostEncodeTimeMs} \n ${this.PreEncodeTimeMs}`);
60
53
  this.EncodeMs = this.PostEncodeTimeMs - this.PreEncodeTimeMs;
61
54
  }
62
55
 
@@ -64,13 +57,10 @@ export class LatencyTestResults {
64
57
  this.CaptureToSendMs == null &&
65
58
  (this.PreCaptureTimeMs != null || this.PostCaptureTimeMs != null)
66
59
  ) {
67
- Logger.Log(
68
- Logger.GetStackTrace(),
69
- `Setting CaptureToSendMs Ms \n ${this.PostCaptureTimeMs} \n ${this.PreCaptureTimeMs}`,
70
- 6
60
+ Logger.Info(
61
+ `Setting CaptureToSendMs Ms \n ${this.PostCaptureTimeMs} \n ${this.PreCaptureTimeMs}`
71
62
  );
72
- this.CaptureToSendMs =
73
- this.PostCaptureTimeMs - this.PreCaptureTimeMs;
63
+ this.CaptureToSendMs = this.PostCaptureTimeMs - this.PreCaptureTimeMs;
74
64
  }
75
65
  }
76
66
  }
@@ -53,9 +53,7 @@ export class FreezeFrame {
53
53
  * @param jpeg - the freeze frame image as a byte array data
54
54
  */
55
55
  updateImageElementSource(jpeg: Uint8Array) {
56
- const base64 = btoa(
57
- jpeg.reduce((data, byte) => data + String.fromCharCode(byte), '')
58
- );
56
+ const base64 = btoa(jpeg.reduce((data, byte) => data + String.fromCharCode(byte), ''));
59
57
  this.imageElement.src = 'data:image/jpeg;base64,' + base64;
60
58
  }
61
59
 
@@ -77,28 +75,18 @@ export class FreezeFrame {
77
75
  let displayHeight = 0;
78
76
  let displayTop = 0;
79
77
  let displayLeft = 0;
80
- const parentAspectRatio =
81
- this.rootDiv.clientWidth / this.rootDiv.clientHeight;
82
- const videoAspectRatio =
83
- this.freezeFrameWidth / this.freezeFrameHeight;
78
+ const parentAspectRatio = this.rootDiv.clientWidth / this.rootDiv.clientHeight;
79
+ const videoAspectRatio = this.freezeFrameWidth / this.freezeFrameHeight;
84
80
  if (parentAspectRatio < videoAspectRatio) {
85
81
  displayWidth = this.rootDiv.clientWidth;
86
- displayHeight = Math.floor(
87
- this.rootDiv.clientWidth / videoAspectRatio
88
- );
89
- displayTop = Math.floor(
90
- (this.rootDiv.clientHeight - displayHeight) * 0.5
91
- );
82
+ displayHeight = Math.floor(this.rootDiv.clientWidth / videoAspectRatio);
83
+ displayTop = Math.floor((this.rootDiv.clientHeight - displayHeight) * 0.5);
92
84
  displayLeft = 0;
93
85
  } else {
94
- displayWidth = Math.floor(
95
- this.rootDiv.clientHeight * videoAspectRatio
96
- );
86
+ displayWidth = Math.floor(this.rootDiv.clientHeight * videoAspectRatio);
97
87
  displayHeight = this.rootDiv.clientHeight;
98
88
  displayTop = 0;
99
- displayLeft = Math.floor(
100
- (this.rootDiv.clientWidth - displayWidth) * 0.5
101
- );
89
+ displayLeft = Math.floor((this.rootDiv.clientWidth - displayWidth) * 0.5);
102
90
  }
103
91
  this.rootElement.style.width = this.rootDiv.offsetWidth + 'px';
104
92
  this.rootElement.style.height = this.rootDiv.offsetHeight + 'px';
@@ -83,30 +83,19 @@ export class FreezeFrameController {
83
83
  else {
84
84
  this.jpeg = jpegBytes;
85
85
  this.receiving = true;
86
- Logger.Log(
87
- Logger.GetStackTrace(),
88
- `received first chunk of freeze frame: ${this.jpeg.length}/${this.size}`,
89
- 6
90
- );
86
+ Logger.Info(`received first chunk of freeze frame: ${this.jpeg.length}/${this.size}`);
91
87
  }
92
88
 
93
89
  // Finished receiving freeze frame, we can show it now
94
90
  if (this.jpeg.length === this.size) {
95
91
  this.receiving = false;
96
92
  this.valid = true;
97
- Logger.Log(
98
- Logger.GetStackTrace(),
99
- `received complete freeze frame ${this.size}`,
100
- 6
101
- );
93
+ Logger.Info(`received complete freeze frame ${this.size}`);
102
94
  this.updateFreezeFrameAndShow(this.jpeg, onLoadCallBack);
103
95
  }
104
96
  // We received more data than the freeze frame payload message indicate (this is an error)
105
97
  else if (this.jpeg.length > this.size) {
106
- Logger.Error(
107
- Logger.GetStackTrace(),
108
- `received bigger freeze frame than advertised: ${this.jpeg.length}/${this.size}`
109
- );
98
+ Logger.Error(`received bigger freeze frame than advertised: ${this.jpeg.length}/${this.size}`);
110
99
  this.jpeg = undefined;
111
100
  this.receiving = false;
112
101
  }
@@ -1,142 +1,148 @@
1
1
  // Copyright Epic Games, Inc. All Rights Reserved.
2
2
 
3
- import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
4
3
  import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
5
- import { EventListenerTracker } from '../Util/EventListenerTracker';
6
- import { Controller } from './GamepadTypes';
4
+ import { IInputController } from './IInputController';
5
+ import { Controller, deepCopyGamepad } from './GamepadTypes';
7
6
 
8
7
  /**
9
- * The class that handles the functionality of gamepads and controllers
8
+ * Additional types for Window and Navigator
9
+ */
10
+ declare global {
11
+ interface Window {
12
+ mozRequestAnimationFrame(callback: FrameRequestCallback): number;
13
+ webkitRequestAnimationFrame(callback: FrameRequestCallback): number;
14
+ }
15
+
16
+ interface Navigator {
17
+ webkitGetGamepads(): Gamepad[];
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Gamepad layout codes enum
23
+ */
24
+ /* eslint-disable @typescript-eslint/no-duplicate-enum-values */
25
+ export enum GamepadLayout {
26
+ RightClusterBottomButton = 0,
27
+ RightClusterRightButton = 1,
28
+ RightClusterLeftButton = 2,
29
+ RightClusterTopButton = 3,
30
+ LeftShoulder = 4,
31
+ RightShoulder = 5,
32
+ LeftTrigger = 6,
33
+ RightTrigger = 7,
34
+ SelectOrBack = 8,
35
+ StartOrForward = 9,
36
+ LeftAnalogPress = 10,
37
+ RightAnalogPress = 11,
38
+ LeftClusterTopButton = 12,
39
+ LeftClusterBottomButton = 13,
40
+ LeftClusterLeftButton = 14,
41
+ LeftClusterRightButton = 15,
42
+ CentreButton = 16,
43
+ // Axes
44
+ LeftStickHorizontal = 0,
45
+ LeftStickVertical = 1,
46
+ RightStickHorizontal = 2,
47
+ RightStickVertical = 3
48
+ }
49
+ /* eslint-enable @typescript-eslint/no-duplicate-enum-values */
50
+
51
+ /**
52
+ * Handles gamepad events from the document to send to the streamer.
10
53
  */
11
- export class GamePadController {
54
+ export class GamepadController implements IInputController {
12
55
  controllers: Array<Controller>;
13
- requestAnimationFrame: (callback: FrameRequestCallback) => number;
14
- toStreamerMessagesProvider: StreamMessageController;
56
+ streamMessageController: StreamMessageController;
15
57
 
16
- // Utility for keeping track of event handlers and to unregister them.
17
- private gamePadEventListenerTracker = new EventListenerTracker();
58
+ onGamepadConnectedListener: (event: GamepadEvent) => void;
59
+ onGamepadDisconnectedListener: (event: GamepadEvent) => void;
60
+ beforeUnloadListener: (event: Event) => void;
61
+ requestAnimationFrame: (callback: FrameRequestCallback) => number;
18
62
 
19
- /**
20
- * @param toStreamerMessagesProvider - Stream message instance
21
- */
22
- constructor(toStreamerMessagesProvider: StreamMessageController) {
23
- this.toStreamerMessagesProvider = toStreamerMessagesProvider;
63
+ constructor(streamMessageController: StreamMessageController) {
64
+ this.streamMessageController = streamMessageController;
24
65
 
66
+ this.onGamepadConnectedListener = this.onGamepadConnected.bind(this);
67
+ this.onGamepadDisconnectedListener = this.onGamepadDisconnected.bind(this);
68
+ this.beforeUnloadListener = this.onBeforeUnload.bind(this);
25
69
  this.requestAnimationFrame = (
26
70
  window.mozRequestAnimationFrame ||
27
71
  window.webkitRequestAnimationFrame ||
28
72
  window.requestAnimationFrame
29
73
  ).bind(window);
30
- const browserWindow = window as Window;
74
+ }
31
75
 
32
- const onBeforeUnload = (ev: Event) =>
33
- this.onBeforeUnload(ev);
34
- window.addEventListener('beforeunload', onBeforeUnload);
76
+ register() {
77
+ window.addEventListener('beforeunload', this.beforeUnloadListener);
35
78
 
79
+ const browserWindow = window as Window;
36
80
  if ('GamepadEvent' in browserWindow) {
37
- const onGamePadConnected = (ev: GamepadEvent) =>
38
- this.gamePadConnectHandler(ev);
39
- const onGamePadDisconnected = (ev: GamepadEvent) =>
40
- this.gamePadDisconnectHandler(ev);
41
- window.addEventListener('gamepadconnected', onGamePadConnected);
42
- window.addEventListener('gamepaddisconnected', onGamePadDisconnected);
43
- this.gamePadEventListenerTracker.addUnregisterCallback(
44
- () => window.removeEventListener('gamepadconnected', onGamePadConnected)
45
- );
46
- this.gamePadEventListenerTracker.addUnregisterCallback(
47
- () => window.removeEventListener('gamepaddisconnected', onGamePadDisconnected)
48
- );
81
+ window.addEventListener('gamepadconnected', this.onGamepadConnectedListener);
82
+ window.addEventListener('gamepaddisconnected', this.onGamepadDisconnectedListener);
49
83
  } else if ('WebKitGamepadEvent' in browserWindow) {
50
- const onWebkitGamePadConnected = (ev: GamepadEvent) => this.gamePadConnectHandler(ev);
51
- const onWebkitGamePadDisconnected = (ev: GamepadEvent) => this.gamePadDisconnectHandler(ev);
52
- window.addEventListener('webkitgamepadconnected', onWebkitGamePadConnected);
53
- window.addEventListener('webkitgamepaddisconnected', onWebkitGamePadDisconnected);
54
- this.gamePadEventListenerTracker.addUnregisterCallback(
55
- () => window.removeEventListener('webkitgamepadconnected', onWebkitGamePadConnected)
56
- );
57
- this.gamePadEventListenerTracker.addUnregisterCallback(
58
- () => window.removeEventListener('webkitgamepaddisconnected', onWebkitGamePadDisconnected)
59
- );
84
+ window.addEventListener('webkitgamepadconnected', this.onGamepadConnectedListener);
85
+ window.addEventListener('webkitgamepaddisconnected', this.onGamepadDisconnectedListener);
60
86
  }
61
87
  this.controllers = [];
62
88
  if (navigator.getGamepads) {
63
89
  for (const gamepad of navigator.getGamepads()) {
64
90
  if (gamepad) {
65
- this.gamePadConnectHandler(new GamepadEvent('gamepadconnected', { gamepad }));
91
+ this.onGamepadConnected(new GamepadEvent('gamepadconnected', { gamepad }));
66
92
  }
67
93
  }
68
94
  }
69
95
  }
70
96
 
71
- /**
72
- * Unregister all event handlers.
73
- */
74
- unregisterGamePadEvents() {
75
- this.gamePadEventListenerTracker.unregisterAll();
76
- for(const controller of this.controllers) {
77
- if(controller.id !== undefined) {
78
- this.onGamepadDisconnected(controller.id);
97
+ unregister() {
98
+ window.removeEventListener('gamepadconnected', this.onGamepadConnectedListener);
99
+ window.removeEventListener('gamepaddisconnected', this.onGamepadDisconnectedListener);
100
+ window.removeEventListener('webkitgamepadconnected', this.onGamepadConnectedListener);
101
+ window.removeEventListener('webkitgamepaddisconnected', this.onGamepadDisconnectedListener);
102
+ for (const controller of this.controllers) {
103
+ if (controller.id !== undefined) {
104
+ this.streamMessageController.toStreamerHandlers.get('GamepadDisconnected')([controller.id]);
79
105
  }
80
106
  }
81
107
  this.controllers = [];
82
- this.onGamepadConnected = () => { /* */ };
83
- this.onGamepadDisconnected = () => { /* */ };
84
108
  }
85
109
 
86
- /**
87
- * Connects the gamepad handler
88
- * @param gamePadEvent - the activating gamepad event
89
- */
90
- gamePadConnectHandler(gamePadEvent: GamepadEvent) {
91
- Logger.Log(Logger.GetStackTrace(), 'Gamepad connect handler', 6);
92
- const gamepad = gamePadEvent.gamepad;
110
+ onGamepadResponseReceived(gamepadId: number) {
111
+ for (const controller of this.controllers) {
112
+ if (controller.id === undefined) {
113
+ controller.id = gamepadId;
114
+ break;
115
+ }
116
+ }
117
+ }
93
118
 
94
- const temp: Controller = {
95
- currentState: gamepad,
96
- prevState: gamepad,
119
+ private onGamepadConnected(event: GamepadEvent) {
120
+ const gamepad = event.gamepad;
121
+ const newController: Controller = {
122
+ currentState: deepCopyGamepad(gamepad),
123
+ prevState: deepCopyGamepad(gamepad),
97
124
  id: undefined
98
125
  };
99
126
 
100
- this.controllers.push(temp);
101
- this.controllers[gamepad.index].currentState = gamepad;
102
- this.controllers[gamepad.index].prevState = gamepad;
103
- Logger.Log(
104
- Logger.GetStackTrace(),
105
- 'gamepad: ' + gamepad.id + ' connected',
106
- 6
107
- );
127
+ this.controllers[gamepad.index] = newController;
108
128
  window.requestAnimationFrame(() => this.updateStatus());
109
- this.onGamepadConnected();
129
+ this.streamMessageController.toStreamerHandlers.get('GamepadConnected')();
110
130
  }
111
131
 
112
- /**
113
- * Disconnects the gamepad handler
114
- * @param gamePadEvent - the activating gamepad event
115
- */
116
- gamePadDisconnectHandler(gamePadEvent: GamepadEvent) {
117
- Logger.Log(Logger.GetStackTrace(), 'Gamepad disconnect handler', 6);
118
- Logger.Log(
119
- Logger.GetStackTrace(),
120
- 'gamepad: ' + gamePadEvent.gamepad.id + ' disconnected',
121
- 6
122
- );
123
- const deletedController = this.controllers[gamePadEvent.gamepad.index];
124
- delete this.controllers[gamePadEvent.gamepad.index];
125
- this.controllers = this.controllers.filter(
126
- (controller) => controller !== undefined
127
- );
128
- this.onGamepadDisconnected(deletedController.id);
132
+ private onGamepadDisconnected(event: GamepadEvent) {
133
+ const gamepad = event.gamepad;
134
+ const deletedController = this.controllers[gamepad.index];
135
+ delete this.controllers[gamepad.index];
136
+ this.controllers = this.controllers.filter((controller) => controller !== undefined);
137
+ this.streamMessageController.toStreamerHandlers.get('GamepadDisconnected')([deletedController.id]);
129
138
  }
130
139
 
131
- /**
132
- * Scan for connected gamepads
133
- */
134
- scanGamePads() {
140
+ private scanGamepads() {
135
141
  const gamepads = navigator.getGamepads
136
142
  ? navigator.getGamepads()
137
143
  : navigator.webkitGetGamepads
138
- ? navigator.webkitGetGamepads()
139
- : [];
144
+ ? navigator.webkitGetGamepads()
145
+ : [];
140
146
  for (let i = 0; i < gamepads.length; i++) {
141
147
  if (gamepads[i] && gamepads[i].index in this.controllers) {
142
148
  this.controllers[gamepads[i].index].currentState = gamepads[i];
@@ -144,38 +150,27 @@ export class GamePadController {
144
150
  }
145
151
  }
146
152
 
147
- /**
148
- * Updates the status of the gamepad and sends the inputs
149
- */
150
- updateStatus() {
151
- this.scanGamePads();
152
- const toStreamerHandlers =
153
- this.toStreamerMessagesProvider.toStreamerHandlers;
153
+ private updateStatus() {
154
+ this.scanGamepads();
155
+ const toStreamerHandlers = this.streamMessageController.toStreamerHandlers;
154
156
 
155
157
  // Iterate over multiple controllers in the case the multiple gamepads are connected
156
158
  for (const controller of this.controllers) {
157
159
  // If we haven't received an id (possible if using an older version of UE), return to original functionality
158
- const controllerIndex = (controller.id === undefined) ? this.controllers.indexOf(controller) : controller.id;
160
+ const controllerIndex =
161
+ controller.id === undefined ? this.controllers.indexOf(controller) : controller.id;
159
162
  const currentState = controller.currentState;
160
163
  for (let i = 0; i < controller.currentState.buttons.length; i++) {
161
164
  const currentButton = controller.currentState.buttons[i];
162
165
  const previousButton = controller.prevState.buttons[i];
163
166
  if (currentButton.pressed) {
164
167
  // press
165
- if (i == gamepadLayout.LeftTrigger) {
166
- // UEs left analog has a button index of 5
167
- toStreamerHandlers.get('GamepadAnalog')([
168
- controllerIndex,
169
- 5,
170
- currentButton.value
171
- ]);
172
- } else if (i == gamepadLayout.RightTrigger) {
173
- // UEs right analog has a button index of 6
174
- toStreamerHandlers.get('GamepadAnalog')([
175
- controllerIndex,
176
- 6,
177
- currentButton.value
178
- ]);
168
+ if (i == GamepadLayout.LeftTrigger) {
169
+ // UEs left analog has a button index of 5
170
+ toStreamerHandlers.get('GamepadAnalog')([controllerIndex, 5, currentButton.value]);
171
+ } else if (i == GamepadLayout.RightTrigger) {
172
+ // UEs right analog has a button index of 6
173
+ toStreamerHandlers.get('GamepadAnalog')([controllerIndex, 6, currentButton.value]);
179
174
  } else {
180
175
  toStreamerHandlers.get('GamepadButtonPressed')([
181
176
  controllerIndex,
@@ -185,26 +180,14 @@ export class GamePadController {
185
180
  }
186
181
  } else if (!currentButton.pressed && previousButton.pressed) {
187
182
  // release
188
- if (i == gamepadLayout.LeftTrigger) {
189
- // UEs left analog has a button index of 5
190
- toStreamerHandlers.get('GamepadAnalog')([
191
- controllerIndex,
192
- 5,
193
- 0
194
- ]);
195
- } else if (i == gamepadLayout.RightTrigger) {
196
- // UEs right analog has a button index of 6
197
- toStreamerHandlers.get('GamepadAnalog')([
198
- controllerIndex,
199
- 6,
200
- 0
201
- ]);
183
+ if (i == GamepadLayout.LeftTrigger) {
184
+ // UEs left analog has a button index of 5
185
+ toStreamerHandlers.get('GamepadAnalog')([controllerIndex, 5, 0]);
186
+ } else if (i == GamepadLayout.RightTrigger) {
187
+ // UEs right analog has a button index of 6
188
+ toStreamerHandlers.get('GamepadAnalog')([controllerIndex, 6, 0]);
202
189
  } else {
203
- toStreamerHandlers.get('GamepadButtonReleased')([
204
- controllerIndex,
205
- i,
206
- 0
207
- ]);
190
+ toStreamerHandlers.get('GamepadButtonReleased')([controllerIndex, i, 0]);
208
191
  }
209
192
  }
210
193
  }
@@ -218,102 +201,21 @@ export class GamePadController {
218
201
  const y = -parseFloat(currentState.axes[i + 1].toFixed(4));
219
202
 
220
203
  // UE's analog axes follow the same order as the browsers, but start at index 1 so we will offset as such
221
- toStreamerHandlers.get('GamepadAnalog')([
222
- controllerIndex,
223
- i + 1,
224
- x
225
- ]); // Horizontal axes, only offset by 1
226
- toStreamerHandlers.get('GamepadAnalog')([
227
- controllerIndex,
228
- i + 2,
229
- y
230
- ]); // Vertical axes, offset by two (1 to match UEs axes convention and then another 1 for the vertical axes)
204
+ toStreamerHandlers.get('GamepadAnalog')([controllerIndex, i + 1, x]); // Horizontal axes, only offset by 1
205
+ toStreamerHandlers.get('GamepadAnalog')([controllerIndex, i + 2, y]); // Vertical axes, offset by two (1 to match UEs axes convention and then another 1 for the vertical axes)
231
206
  }
232
- this.controllers[controllerIndex].prevState = currentState;
207
+ this.controllers[controllerIndex].prevState = deepCopyGamepad(currentState);
233
208
  }
234
209
  if (this.controllers.length > 0) {
235
210
  this.requestAnimationFrame(() => this.updateStatus());
236
211
  }
237
212
  }
238
213
 
239
- onGamepadResponseReceived(gamepadId: number) {
240
- for(const controller of this.controllers) {
241
- if(controller.id === undefined) {
242
- controller.id = gamepadId;
243
- break;
244
- }
245
- }
246
- }
247
-
248
- /**
249
- * Event to send the gamepadconnected message to the application
250
- */
251
- onGamepadConnected() {
252
- // Default Functionality: Do Nothing
253
- }
254
-
255
- /**
256
- * Event to send the gamepaddisconnected message to the application
257
- */
258
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
259
- onGamepadDisconnected(controllerIdx: number) {
260
- // Default Functionality: Do Nothing
261
- }
262
-
263
- onBeforeUnload(_: Event) {
214
+ private onBeforeUnload(_: Event) {
264
215
  // When a user navigates away from the page, we need to inform UE of all the disconnecting
265
216
  // controllers
266
- for(const controller of this.controllers) {
267
- this.onGamepadDisconnected(controller.id);
217
+ for (const controller of this.controllers) {
218
+ this.streamMessageController.toStreamerHandlers.get('GamepadDisconnected')([controller.id]);
268
219
  }
269
220
  }
270
221
  }
271
-
272
-
273
-
274
- /**
275
- * Additional types for Window and Navigator
276
- */
277
- declare global {
278
- interface Window {
279
- mozRequestAnimationFrame(callback: FrameRequestCallback): number;
280
- webkitRequestAnimationFrame(callback: FrameRequestCallback): number;
281
- }
282
-
283
- interface Navigator {
284
- webkitGetGamepads(): Gamepad[];
285
- }
286
- }
287
-
288
- /* eslint-disable @typescript-eslint/no-duplicate-enum-values */
289
-
290
- /**
291
- * Gamepad layout codes enum
292
- */
293
- export enum gamepadLayout {
294
- RightClusterBottomButton = 0,
295
- RightClusterRightButton = 1,
296
- RightClusterLeftButton = 2,
297
- RightClusterTopButton = 3,
298
- LeftShoulder = 4,
299
- RightShoulder = 5,
300
- LeftTrigger = 6,
301
- RightTrigger = 7,
302
- SelectOrBack = 8,
303
- StartOrForward = 9,
304
- LeftAnalogPress = 10,
305
- RightAnalogPress = 11,
306
- LeftClusterTopButton = 12,
307
- LeftClusterBottomButton = 13,
308
- LeftClusterLeftButton = 14,
309
- LeftClusterRightButton = 15,
310
- CentreButton = 16,
311
- // Axes
312
- LeftStickHorizontal = 0,
313
- LeftStickVertical = 1,
314
- RightStickHorizontal = 2,
315
- RightStickVertical = 3
316
- }
317
-
318
- /* eslint-enable @typescript-eslint/no-duplicate-enum-values */
319
-
@@ -8,3 +8,26 @@ export interface Controller {
8
8
  prevState: Gamepad;
9
9
  id: number | undefined;
10
10
  }
11
+
12
+ /**
13
+ * Deep copies the values from a gamepad by first converting it to a JSON object and then back to a gamepad
14
+ *
15
+ * @param gamepad the original gamepad
16
+ * @returns a new gamepad object, populated with the original gamepads values
17
+ */
18
+ export function deepCopyGamepad(gamepad: Gamepad): Gamepad {
19
+ return JSON.parse(
20
+ JSON.stringify({
21
+ buttons: gamepad.buttons.map((b) =>
22
+ JSON.parse(
23
+ JSON.stringify({
24
+ pressed: b.pressed,
25
+ touched: b.touched,
26
+ value: b.value
27
+ })
28
+ )
29
+ ),
30
+ axes: gamepad.axes
31
+ })
32
+ );
33
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The base interface for all input controllers.
3
+ * Since controllers mostly just register events and handle them the external interface is limited
4
+ * to register/unregister
5
+ */
6
+ export interface IInputController {
7
+ /**
8
+ * Tells the controller to register itself to the events it needs to operate.
9
+ */
10
+ register(): void;
11
+
12
+ /**
13
+ * Tells the cnotroller to unregister from the events it previously registered to.
14
+ * No behaviour through the controller should happen past this point until register is called again.
15
+ */
16
+ unregister(): void;
17
+ }