@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.0.5

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 (138) hide show
  1. package/.cspell.json +48 -0
  2. package/.eslintignore +8 -0
  3. package/.eslintrc.js +8 -0
  4. package/.prettierignore +0 -0
  5. package/.prettierrc.json +6 -0
  6. package/dist/lib-pixelstreamingfrontend.esm.js +1 -0
  7. package/dist/lib-pixelstreamingfrontend.js +1 -0
  8. package/jest.config.js +18 -0
  9. package/package.json +48 -0
  10. package/readme.md +15 -0
  11. package/src/AFK/AFKController.test.ts +162 -0
  12. package/src/AFK/AFKController.ts +158 -0
  13. package/src/Config/Config.test.ts +222 -0
  14. package/src/Config/Config.ts +970 -0
  15. package/src/Config/SettingBase.ts +65 -0
  16. package/src/Config/SettingFlag.ts +99 -0
  17. package/src/Config/SettingNumber.ts +111 -0
  18. package/src/Config/SettingOption.ts +124 -0
  19. package/src/Config/SettingText.ts +82 -0
  20. package/src/DataChannel/DataChannelController.ts +138 -0
  21. package/src/DataChannel/DataChannelLatencyTestController.ts +129 -0
  22. package/src/DataChannel/DataChannelLatencyTestResults.ts +67 -0
  23. package/src/DataChannel/DataChannelSender.ts +59 -0
  24. package/src/DataChannel/InitialSettings.ts +61 -0
  25. package/src/DataChannel/LatencyTestResults.ts +76 -0
  26. package/src/FreezeFrame/FreezeFrame.ts +114 -0
  27. package/src/FreezeFrame/FreezeFrameController.ts +114 -0
  28. package/src/Inputs/FakeTouchController.ts +199 -0
  29. package/src/Inputs/GamepadController.ts +314 -0
  30. package/src/Inputs/GamepadTypes.ts +10 -0
  31. package/src/Inputs/HoveringMouseEvents.ts +192 -0
  32. package/src/Inputs/IMouseEvents.ts +64 -0
  33. package/src/Inputs/ITouchController.ts +29 -0
  34. package/src/Inputs/InputClassesFactory.ts +140 -0
  35. package/src/Inputs/KeyboardController.ts +354 -0
  36. package/src/Inputs/LockedMouseEvents.ts +287 -0
  37. package/src/Inputs/MouseButtons.ts +25 -0
  38. package/src/Inputs/MouseController.ts +362 -0
  39. package/src/Inputs/SpecialKeyCodes.ts +16 -0
  40. package/src/Inputs/TouchController.ts +208 -0
  41. package/src/Inputs/XRGamepadController.ts +126 -0
  42. package/src/PeerConnectionController/AggregatedStats.ts +311 -0
  43. package/src/PeerConnectionController/CandidatePairStats.ts +17 -0
  44. package/src/PeerConnectionController/CandidateStat.ts +13 -0
  45. package/src/PeerConnectionController/CodecStats.ts +19 -0
  46. package/src/PeerConnectionController/DataChannelStats.ts +17 -0
  47. package/src/PeerConnectionController/InboundRTPStats.ts +154 -0
  48. package/src/PeerConnectionController/InboundTrackStats.ts +34 -0
  49. package/src/PeerConnectionController/OutBoundRTPStats.ts +26 -0
  50. package/src/PeerConnectionController/PeerConnectionController.ts +563 -0
  51. package/src/PeerConnectionController/SessionStats.ts +10 -0
  52. package/src/PeerConnectionController/StreamStats.ts +11 -0
  53. package/src/PixelStreaming/PixelStreaming.test.ts +626 -0
  54. package/src/PixelStreaming/PixelStreaming.ts +851 -0
  55. package/src/UI/OnScreenKeyboard.ts +97 -0
  56. package/src/UeInstanceMessage/ResponseController.ts +47 -0
  57. package/src/UeInstanceMessage/SendMessageController.ts +154 -0
  58. package/src/UeInstanceMessage/StreamMessageController.ts +233 -0
  59. package/src/UeInstanceMessage/ToStreamerMessagesController.ts +62 -0
  60. package/src/Util/CoordinateConverter.ts +289 -0
  61. package/src/Util/EventEmitter.ts +611 -0
  62. package/src/Util/EventListenerTracker.ts +29 -0
  63. package/src/Util/FileUtil.ts +140 -0
  64. package/src/Util/RTCUtils.ts +41 -0
  65. package/src/Util/WebGLUtils.ts +49 -0
  66. package/src/Util/WebXRUtils.ts +25 -0
  67. package/src/VideoPlayer/StreamController.ts +89 -0
  68. package/src/VideoPlayer/VideoPlayer.ts +246 -0
  69. package/src/WebRtcPlayer/WebRtcPlayerController.ts +2158 -0
  70. package/src/WebXR/WebXRController.ts +319 -0
  71. package/src/__test__/mockMediaStream.ts +124 -0
  72. package/src/__test__/mockRTCPeerConnection.ts +347 -0
  73. package/src/__test__/mockRTCRtpReceiver.ts +22 -0
  74. package/src/__test__/mockWebSocket.ts +136 -0
  75. package/src/pixelstreamingfrontend.ts +46 -0
  76. package/tsconfig.jest.json +8 -0
  77. package/tsconfig.json +24 -0
  78. package/types/AFK/AFKController.d.ts +39 -0
  79. package/types/Config/Config.d.ts +218 -0
  80. package/types/Config/SettingBase.d.ts +30 -0
  81. package/types/Config/SettingFlag.d.ts +33 -0
  82. package/types/Config/SettingNumber.d.ts +45 -0
  83. package/types/Config/SettingOption.d.ts +43 -0
  84. package/types/Config/SettingText.d.ts +29 -0
  85. package/types/DataChannel/DataChannelController.d.ts +59 -0
  86. package/types/DataChannel/DataChannelLatencyTestController.d.ts +26 -0
  87. package/types/DataChannel/DataChannelLatencyTestResults.d.ts +46 -0
  88. package/types/DataChannel/DataChannelSender.d.ts +21 -0
  89. package/types/DataChannel/InitialSettings.d.ts +44 -0
  90. package/types/DataChannel/LatencyTestResults.d.ts +31 -0
  91. package/types/FreezeFrame/FreezeFrame.d.ts +36 -0
  92. package/types/FreezeFrame/FreezeFrameController.d.ts +37 -0
  93. package/types/Inputs/FakeTouchController.d.ts +61 -0
  94. package/types/Inputs/GamepadController.d.ts +85 -0
  95. package/types/Inputs/GamepadTypes.d.ts +8 -0
  96. package/types/Inputs/HoveringMouseEvents.d.ts +56 -0
  97. package/types/Inputs/IMouseEvents.d.ts +53 -0
  98. package/types/Inputs/ITouchController.d.ts +24 -0
  99. package/types/Inputs/InputClassesFactory.d.ts +54 -0
  100. package/types/Inputs/KeyboardController.d.ts +62 -0
  101. package/types/Inputs/LockedMouseEvents.d.ts +80 -0
  102. package/types/Inputs/MouseButtons.d.ts +22 -0
  103. package/types/Inputs/MouseController.d.ts +75 -0
  104. package/types/Inputs/SpecialKeyCodes.d.ts +14 -0
  105. package/types/Inputs/TouchController.d.ts +53 -0
  106. package/types/Inputs/XRGamepadController.d.ts +15 -0
  107. package/types/PeerConnectionController/AggregatedStats.d.ts +77 -0
  108. package/types/PeerConnectionController/CandidatePairStats.d.ts +15 -0
  109. package/types/PeerConnectionController/CandidateStat.d.ts +11 -0
  110. package/types/PeerConnectionController/CodecStats.d.ts +14 -0
  111. package/types/PeerConnectionController/DataChannelStats.d.ts +15 -0
  112. package/types/PeerConnectionController/InboundRTPStats.d.ts +141 -0
  113. package/types/PeerConnectionController/InboundTrackStats.d.ts +32 -0
  114. package/types/PeerConnectionController/OutBoundRTPStats.d.ts +23 -0
  115. package/types/PeerConnectionController/PeerConnectionController.d.ts +132 -0
  116. package/types/PeerConnectionController/SessionStats.d.ts +8 -0
  117. package/types/PeerConnectionController/StreamStats.d.ts +9 -0
  118. package/types/PixelStreaming/PixelStreaming.d.ts +259 -0
  119. package/types/UI/OnScreenKeyboard.d.ts +31 -0
  120. package/types/UeInstanceMessage/ResponseController.d.ts +19 -0
  121. package/types/UeInstanceMessage/SendMessageController.d.ts +18 -0
  122. package/types/UeInstanceMessage/StreamMessageController.d.ts +29 -0
  123. package/types/UeInstanceMessage/ToStreamerMessagesController.d.ts +32 -0
  124. package/types/Util/CoordinateConverter.d.ts +100 -0
  125. package/types/Util/EventEmitter.d.ts +422 -0
  126. package/types/Util/EventListenerTracker.d.ts +14 -0
  127. package/types/Util/FileUtil.d.ts +32 -0
  128. package/types/Util/RTCUtils.d.ts +8 -0
  129. package/types/Util/WebGLUtils.d.ts +4 -0
  130. package/types/Util/WebXRUtils.d.ts +9 -0
  131. package/types/VideoPlayer/StreamController.d.ts +24 -0
  132. package/types/VideoPlayer/VideoPlayer.d.ts +78 -0
  133. package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +377 -0
  134. package/types/WebXR/WebXRController.d.ts +26 -0
  135. package/types/pixelstreamingfrontend.d.ts +22 -0
  136. package/webpack.common.js +35 -0
  137. package/webpack.dev.js +35 -0
  138. package/webpack.prod.js +36 -0
@@ -0,0 +1,362 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ import { MouseButtonsMask, MouseButton } from './MouseButtons';
4
+ import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
5
+ import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
6
+ import { CoordinateConverter } from '../Util/CoordinateConverter';
7
+ import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
8
+ import { IMouseEvents } from './IMouseEvents';
9
+ import { LockedMouseEvents } from './LockedMouseEvents';
10
+ import { HoveringMouseEvents } from './HoveringMouseEvents';
11
+ import type { ActiveKeys } from './InputClassesFactory';
12
+ import { EventListenerTracker } from '../Util/EventListenerTracker';
13
+
14
+ /**
15
+ * Handles the Mouse Inputs for the document
16
+ */
17
+ export class MouseController {
18
+ videoElementProvider: VideoPlayer;
19
+ toStreamerMessagesProvider: StreamMessageController;
20
+ coordinateConverter: CoordinateConverter;
21
+ activeKeysProvider: ActiveKeys;
22
+
23
+ // Utility for keeping track of event handlers and unregistering them
24
+ private mouseEventListenerTracker = new EventListenerTracker();
25
+
26
+ /**
27
+ * @param toStreamerMessagesProvider - Stream message instance
28
+ * @param videoElementProvider - Video Player instance
29
+ * @param normalizeAndQuantize - A normalize and quantize instance
30
+ */
31
+ constructor(
32
+ toStreamerMessagesProvider: StreamMessageController,
33
+ videoElementProvider: VideoPlayer,
34
+ coordinateConverter: CoordinateConverter,
35
+ activeKeysProvider: ActiveKeys
36
+ ) {
37
+ this.toStreamerMessagesProvider = toStreamerMessagesProvider;
38
+ this.coordinateConverter = coordinateConverter;
39
+ this.videoElementProvider = videoElementProvider;
40
+ this.activeKeysProvider = activeKeysProvider;
41
+ this.registerMouseEnterAndLeaveEvents();
42
+ }
43
+
44
+ /**
45
+ * Clears all the click events on the current video element parent div
46
+ */
47
+ unregisterMouseEvents() {
48
+ this.mouseEventListenerTracker.unregisterAll();
49
+ }
50
+
51
+ /**
52
+ * Register a locked mouse class
53
+ * @param mouseController - a mouse controller instance
54
+ * @param playerStyleAttributesProvider - a player style attributes instance
55
+ */
56
+ registerLockedMouseEvents(mouseController: MouseController) {
57
+ const videoElementParent =
58
+ this.videoElementProvider.getVideoParentElement() as HTMLDivElement;
59
+ const lockedMouseEvents: IMouseEvents = new LockedMouseEvents(
60
+ this.videoElementProvider,
61
+ mouseController,
62
+ this.activeKeysProvider
63
+ );
64
+
65
+ videoElementParent.requestPointerLock =
66
+ videoElementParent.requestPointerLock ||
67
+ videoElementParent.mozRequestPointerLock;
68
+ document.exitPointerLock =
69
+ document.exitPointerLock || document.mozExitPointerLock;
70
+
71
+ // minor hack to alleviate ios not supporting pointerlock
72
+ if (videoElementParent.requestPointerLock) {
73
+ const onclick = () => {
74
+ videoElementParent.requestPointerLock();
75
+ };
76
+ videoElementParent.addEventListener('click', onclick);
77
+ this.mouseEventListenerTracker.addUnregisterCallback(
78
+ () => videoElementParent.removeEventListener('click', onclick)
79
+ );
80
+ }
81
+
82
+ const lockStateChangeListener = () =>
83
+ lockedMouseEvents.lockStateChange();
84
+ document.addEventListener(
85
+ 'pointerlockchange',
86
+ lockStateChangeListener,
87
+ false
88
+ );
89
+ document.addEventListener(
90
+ 'mozpointerlockchange',
91
+ lockStateChangeListener,
92
+ false
93
+ );
94
+ this.mouseEventListenerTracker.addUnregisterCallback(
95
+ () => document.removeEventListener(
96
+ 'pointerlockchange',
97
+ lockStateChangeListener,
98
+ false
99
+ )
100
+ );
101
+ this.mouseEventListenerTracker.addUnregisterCallback(
102
+ () => document.removeEventListener(
103
+ 'mozpointerlockchange',
104
+ lockStateChangeListener,
105
+ false
106
+ )
107
+ );
108
+
109
+ const onmousedown = (mouseEvent: MouseEvent) =>
110
+ lockedMouseEvents.handleMouseDown(mouseEvent);
111
+ const onmouseup = (mouseEvent: MouseEvent) =>
112
+ lockedMouseEvents.handleMouseUp(mouseEvent);
113
+ const onwheel = (wheelEvent: WheelEvent) =>
114
+ lockedMouseEvents.handleMouseWheel(wheelEvent);
115
+ const ondblclick = (mouseEvent: MouseEvent) =>
116
+ lockedMouseEvents.handleMouseDouble(mouseEvent);
117
+ videoElementParent.addEventListener('mousedown', onmousedown);
118
+ videoElementParent.addEventListener('mouseup', onmouseup);
119
+ videoElementParent.addEventListener('wheel', onwheel);
120
+ videoElementParent.addEventListener('dblclick', ondblclick);
121
+
122
+ this.mouseEventListenerTracker.addUnregisterCallback(
123
+ () => videoElementParent.removeEventListener('mousedown', onmousedown)
124
+ );
125
+ this.mouseEventListenerTracker.addUnregisterCallback(
126
+ () => videoElementParent.removeEventListener('mouseup', onmouseup)
127
+ );
128
+ this.mouseEventListenerTracker.addUnregisterCallback(
129
+ () => videoElementParent.removeEventListener('wheel', onwheel)
130
+ );
131
+ this.mouseEventListenerTracker.addUnregisterCallback(
132
+ () => videoElementParent.removeEventListener('dblclick', ondblclick)
133
+ );
134
+ this.mouseEventListenerTracker.addUnregisterCallback(
135
+ () => lockedMouseEvents.unregisterMouseEvents()
136
+ );
137
+ this.mouseEventListenerTracker.addUnregisterCallback(() => {
138
+ if (
139
+ document.exitPointerLock &&
140
+ (document.pointerLockElement === videoElementParent ||
141
+ document.mozPointerLockElement === videoElementParent)
142
+ ) {
143
+ document.exitPointerLock();
144
+ }
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Register a hovering mouse class
150
+ * @param mouseController - A mouse controller object
151
+ */
152
+ registerHoveringMouseEvents(mouseController: MouseController) {
153
+ const videoElementParent =
154
+ this.videoElementProvider.getVideoParentElement() as HTMLDivElement;
155
+ const hoveringMouseEvents = new HoveringMouseEvents(mouseController);
156
+
157
+ const onmousemove = (mouseEvent: MouseEvent) =>
158
+ hoveringMouseEvents.updateMouseMovePosition(mouseEvent);
159
+ const onmousedown = (mouseEvent: MouseEvent) =>
160
+ hoveringMouseEvents.handleMouseDown(mouseEvent);
161
+ const onmouseup = (mouseEvent: MouseEvent) =>
162
+ hoveringMouseEvents.handleMouseUp(mouseEvent);
163
+ const oncontextmenu = (mouseEvent: MouseEvent) =>
164
+ hoveringMouseEvents.handleContextMenu(mouseEvent);
165
+ const onwheel = (wheelEvent: WheelEvent) =>
166
+ hoveringMouseEvents.handleMouseWheel(wheelEvent);
167
+ const ondblclick = (mouseEvent: MouseEvent) =>
168
+ hoveringMouseEvents.handleMouseDouble(mouseEvent);
169
+ videoElementParent.addEventListener('mousemove', onmousemove);
170
+ videoElementParent.addEventListener('mousedown', onmousedown);
171
+ videoElementParent.addEventListener('mouseup', onmouseup);
172
+ videoElementParent.addEventListener('contextmenu', oncontextmenu);
173
+ videoElementParent.addEventListener('wheel', onwheel);
174
+ videoElementParent.addEventListener('dblclick', ondblclick);
175
+
176
+ this.mouseEventListenerTracker.addUnregisterCallback(
177
+ () => videoElementParent.removeEventListener('mousemove', onmousemove)
178
+ );
179
+ this.mouseEventListenerTracker.addUnregisterCallback(
180
+ () => videoElementParent.removeEventListener('mousedown', onmousedown)
181
+ );
182
+ this.mouseEventListenerTracker.addUnregisterCallback(
183
+ () => videoElementParent.removeEventListener('mouseup', onmouseup)
184
+ );
185
+ this.mouseEventListenerTracker.addUnregisterCallback(
186
+ () => videoElementParent.removeEventListener('contextmenu', oncontextmenu)
187
+ );
188
+ this.mouseEventListenerTracker.addUnregisterCallback(
189
+ () => videoElementParent.removeEventListener('wheel', onwheel)
190
+ );
191
+ this.mouseEventListenerTracker.addUnregisterCallback(
192
+ () => videoElementParent.removeEventListener('dblclick', ondblclick)
193
+ );
194
+ this.mouseEventListenerTracker.addUnregisterCallback(
195
+ () => hoveringMouseEvents.unregisterMouseEvents()
196
+ );
197
+ }
198
+
199
+ /**
200
+ * Set the mouse enter and mouse leave events
201
+ */
202
+ registerMouseEnterAndLeaveEvents() {
203
+ const videoElementParent =
204
+ this.videoElementProvider.getVideoParentElement() as HTMLDivElement;
205
+
206
+ // Handle when the Mouse has entered the element
207
+ const onmouseenter = (event: MouseEvent) => {
208
+ if (!this.videoElementProvider.isVideoReady()) {
209
+ return;
210
+ }
211
+ Logger.Log(Logger.GetStackTrace(), 'Mouse Entered', 6);
212
+ this.sendMouseEnter();
213
+ this.pressMouseButtons(event.buttons, event.x, event.y);
214
+ };
215
+
216
+ // Handles when the mouse has left the element
217
+ const onmouseleave = (event: MouseEvent) => {
218
+ if (!this.videoElementProvider.isVideoReady()) {
219
+ return;
220
+ }
221
+ Logger.Log(Logger.GetStackTrace(), 'Mouse Left', 6);
222
+ this.sendMouseLeave();
223
+ this.releaseMouseButtons(event.buttons, event.x, event.y);
224
+ };
225
+ videoElementParent.addEventListener('mouseenter', onmouseenter);
226
+ videoElementParent.addEventListener('mouseleave', onmouseleave);
227
+
228
+ this.mouseEventListenerTracker.addUnregisterCallback(
229
+ () => videoElementParent.removeEventListener('mouseenter', onmouseenter)
230
+ );
231
+ this.mouseEventListenerTracker.addUnregisterCallback(
232
+ () => videoElementParent.removeEventListener('mouseleave', onmouseleave)
233
+ );
234
+ }
235
+
236
+ /**
237
+ * Handle when a mouse button is released
238
+ * @param buttons - Mouse Button
239
+ * @param X - Mouse pointer X coordinate
240
+ * @param Y - Mouse pointer Y coordinate
241
+ */
242
+ releaseMouseButtons(buttons: number, X: number, Y: number) {
243
+ const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(
244
+ X,
245
+ Y
246
+ );
247
+ if (buttons & MouseButtonsMask.primaryButton) {
248
+ this.sendMouseUp(MouseButton.mainButton, coord.x, coord.y);
249
+ }
250
+ if (buttons & MouseButtonsMask.secondaryButton) {
251
+ this.sendMouseUp(MouseButton.secondaryButton, coord.x, coord.y);
252
+ }
253
+ if (buttons & MouseButtonsMask.auxiliaryButton) {
254
+ this.sendMouseUp(MouseButton.auxiliaryButton, coord.x, coord.y);
255
+ }
256
+ if (buttons & MouseButtonsMask.fourthButton) {
257
+ this.sendMouseUp(MouseButton.fourthButton, coord.x, coord.y);
258
+ }
259
+ if (buttons & MouseButtonsMask.fifthButton) {
260
+ this.sendMouseUp(MouseButton.fifthButton, coord.x, coord.y);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Handle when a mouse button is pressed
266
+ * @param buttons - Mouse Button
267
+ * @param X - Mouse pointer X coordinate
268
+ * @param Y - Mouse pointer Y coordinate
269
+ */
270
+ pressMouseButtons(buttons: number, X: number, Y: number) {
271
+ if (!this.videoElementProvider.isVideoReady()) {
272
+ return;
273
+ }
274
+ const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(
275
+ X,
276
+ Y
277
+ );
278
+ if (buttons & MouseButtonsMask.primaryButton) {
279
+ this.sendMouseDown(MouseButton.mainButton, coord.x, coord.y);
280
+ }
281
+ if (buttons & MouseButtonsMask.secondaryButton) {
282
+ this.sendMouseDown(MouseButton.secondaryButton, coord.x, coord.y);
283
+ }
284
+ if (buttons & MouseButtonsMask.auxiliaryButton) {
285
+ this.sendMouseDown(MouseButton.auxiliaryButton, coord.x, coord.y);
286
+ }
287
+ if (buttons & MouseButtonsMask.fourthButton) {
288
+ this.sendMouseDown(MouseButton.fourthButton, coord.x, coord.y);
289
+ }
290
+ if (buttons & MouseButtonsMask.fifthButton) {
291
+ this.sendMouseDown(MouseButton.fifthButton, coord.x, coord.y);
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Handles mouse enter
297
+ */
298
+ sendMouseEnter() {
299
+ if (!this.videoElementProvider.isVideoReady()) {
300
+ return;
301
+ }
302
+ const toStreamerHandlers =
303
+ this.toStreamerMessagesProvider.toStreamerHandlers;
304
+ toStreamerHandlers.get('MouseEnter')();
305
+ }
306
+
307
+ /**
308
+ * Handles mouse Leave
309
+ */
310
+ sendMouseLeave() {
311
+ if (!this.videoElementProvider.isVideoReady()) {
312
+ return;
313
+ }
314
+ const toStreamerHandlers =
315
+ this.toStreamerMessagesProvider.toStreamerHandlers;
316
+ toStreamerHandlers.get('MouseLeave')();
317
+ }
318
+
319
+ /**
320
+ * Handles when a mouse button is pressed down
321
+ * @param button - Mouse Button Pressed
322
+ * @param X - Mouse X Coordinate
323
+ * @param Y - Mouse Y Coordinate
324
+ */
325
+ sendMouseDown(button: number, X: number, Y: number) {
326
+ if (!this.videoElementProvider.isVideoReady()) {
327
+ return;
328
+ }
329
+ Logger.Log(
330
+ Logger.GetStackTrace(),
331
+ `mouse button ${button} down at (${X}, ${Y})`,
332
+ 6
333
+ );
334
+ const toStreamerHandlers =
335
+ this.toStreamerMessagesProvider.toStreamerHandlers;
336
+ toStreamerHandlers.get('MouseDown')([button, X, Y]);
337
+ }
338
+
339
+ /**
340
+ * Handles when a mouse button is pressed up
341
+ * @param button - Mouse Button Pressed
342
+ * @param X - Mouse X Coordinate
343
+ * @param Y - Mouse Y Coordinate
344
+ */
345
+ sendMouseUp(button: number, X: number, Y: number) {
346
+ if (!this.videoElementProvider.isVideoReady()) {
347
+ return;
348
+ }
349
+ Logger.Log(
350
+ Logger.GetStackTrace(),
351
+ `mouse button ${button} up at (${X}, ${Y})`,
352
+ 6
353
+ );
354
+ const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(
355
+ X,
356
+ Y
357
+ );
358
+ const toStreamerHandlers =
359
+ this.toStreamerMessagesProvider.toStreamerHandlers;
360
+ toStreamerHandlers.get('MouseUp')([button, coord.x, coord.y]);
361
+ }
362
+ }
@@ -0,0 +1,16 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ /**
4
+ * Registers the Special Key codes
5
+ * Must be kept in sync with JavaScriptKeyCodeToFKey C++ array.
6
+ * The index of the entry in the array is the special key code given below.
7
+ */
8
+ export class SpecialKeyCodes {
9
+ static backSpace = 8;
10
+ static shift = 16;
11
+ static control = 17;
12
+ static alt = 18;
13
+ static rightShift = 253;
14
+ static rightControl = 254;
15
+ static rightAlt = 255;
16
+ }
@@ -0,0 +1,208 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
4
+ import { CoordinateConverter } from '../Util/CoordinateConverter';
5
+ import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
6
+ import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
7
+ import { ITouchController } from './ITouchController';
8
+ import { EventListenerTracker } from '../Util/EventListenerTracker';
9
+ /**
10
+ * Handles the Touch input Events
11
+ */
12
+ export class TouchController implements ITouchController {
13
+ toStreamerMessagesProvider: StreamMessageController;
14
+ videoElementProvider: VideoPlayer;
15
+ coordinateConverter: CoordinateConverter;
16
+ videoElementParent: HTMLVideoElement;
17
+ fingers = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
18
+ fingerIds = new Map();
19
+ maxByteValue = 255;
20
+
21
+ // Utility for keeping track of event handlers and unregistering them
22
+ private touchEventListenerTracker = new EventListenerTracker();
23
+
24
+ /**
25
+ * @param toStreamerMessagesProvider - Stream message instance
26
+ * @param videoElementProvider - Video Player instance
27
+ * @param coordinateConverter - A coordinate converter instance
28
+ */
29
+ constructor(
30
+ toStreamerMessagesProvider: StreamMessageController,
31
+ videoElementProvider: VideoPlayer,
32
+ coordinateConverter: CoordinateConverter
33
+ ) {
34
+ this.toStreamerMessagesProvider = toStreamerMessagesProvider;
35
+ this.videoElementProvider = videoElementProvider;
36
+ this.coordinateConverter = coordinateConverter;
37
+ this.videoElementParent = videoElementProvider.getVideoElement();
38
+ const ontouchstart = (ev: TouchEvent) =>
39
+ this.onTouchStart(ev);
40
+ const ontouchend = (ev: TouchEvent) =>
41
+ this.onTouchEnd(ev);
42
+ const ontouchmove = (ev: TouchEvent) =>
43
+ this.onTouchMove(ev);
44
+ this.videoElementParent.addEventListener('touchstart', ontouchstart);
45
+ this.videoElementParent.addEventListener('touchend', ontouchend);
46
+ this.videoElementParent.addEventListener('touchmove', ontouchmove);
47
+ this.touchEventListenerTracker.addUnregisterCallback(
48
+ () => this.videoElementParent.removeEventListener('touchstart', ontouchstart)
49
+ );
50
+ this.touchEventListenerTracker.addUnregisterCallback(
51
+ () => this.videoElementParent.removeEventListener('touchend', ontouchend)
52
+ );
53
+ this.touchEventListenerTracker.addUnregisterCallback(
54
+ () => this.videoElementParent.removeEventListener('touchmove', ontouchmove)
55
+ );
56
+ Logger.Log(Logger.GetStackTrace(), 'Touch Events Registered', 6);
57
+
58
+ // is this strictly necessary?
59
+ const preventOnTouchMove = (event: TouchEvent) => {
60
+ event.preventDefault();
61
+ };
62
+ document.addEventListener('touchmove', preventOnTouchMove);
63
+ this.touchEventListenerTracker.addUnregisterCallback(
64
+ () => document.removeEventListener('touchmove', preventOnTouchMove)
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Unregister all touch events
70
+ */
71
+ unregisterTouchEvents() {
72
+ this.touchEventListenerTracker.unregisterAll();
73
+ }
74
+
75
+ /**
76
+ * Remember a touch command
77
+ * @param touch - the touch command
78
+ */
79
+ rememberTouch(touch: Touch) {
80
+ const finger = this.fingers.pop();
81
+ if (finger === undefined) {
82
+ Logger.Log(
83
+ Logger.GetStackTrace(),
84
+ 'exhausted touch identifiers',
85
+ 6
86
+ );
87
+ }
88
+ this.fingerIds.set(touch.identifier, finger);
89
+ }
90
+
91
+ /**
92
+ * Forgets a touch command
93
+ * @param touch - the touch command
94
+ */
95
+ forgetTouch(touch: Touch) {
96
+ this.fingers.push(this.fingerIds.get(touch.identifier));
97
+ // Sort array back into descending order. This means if finger '1' were to lift after finger '0', we would ensure that 0 will be the first index to pop
98
+ this.fingers.sort(function (a, b) {
99
+ return b - a;
100
+ });
101
+ this.fingerIds.delete(touch.identifier);
102
+ }
103
+
104
+ /**
105
+ * When a touch event starts
106
+ * @param touchEvent - the touch event being intercepted
107
+ */
108
+ onTouchStart(touchEvent: TouchEvent) {
109
+ if (!this.videoElementProvider.isVideoReady()) {
110
+ return;
111
+ }
112
+ for (let t = 0; t < touchEvent.changedTouches.length; t++) {
113
+ this.rememberTouch(touchEvent.changedTouches[t]);
114
+ }
115
+ Logger.Log(Logger.GetStackTrace(), 'touch start', 6);
116
+
117
+ this.emitTouchData('TouchStart', touchEvent.changedTouches);
118
+ touchEvent.preventDefault();
119
+ }
120
+
121
+ /**
122
+ * When a touch event ends
123
+ * @param touchEvent - the touch event being intercepted
124
+ */
125
+ onTouchEnd(touchEvent: TouchEvent) {
126
+ if (!this.videoElementProvider.isVideoReady()) {
127
+ return;
128
+ }
129
+ Logger.Log(Logger.GetStackTrace(), 'touch end', 6);
130
+ this.emitTouchData('TouchEnd', touchEvent.changedTouches);
131
+ // Re-cycle unique identifiers previously assigned to each touch.
132
+ for (let t = 0; t < touchEvent.changedTouches.length; t++) {
133
+ this.forgetTouch(touchEvent.changedTouches[t]);
134
+ }
135
+ touchEvent.preventDefault();
136
+ }
137
+
138
+ /**
139
+ * when a moving touch event occurs
140
+ * @param touchEvent - the touch event being intercepted
141
+ */
142
+ onTouchMove(touchEvent: TouchEvent) {
143
+ if (!this.videoElementProvider.isVideoReady()) {
144
+ return;
145
+ }
146
+ Logger.Log(Logger.GetStackTrace(), 'touch move', 6);
147
+ this.emitTouchData('TouchMove', touchEvent.touches);
148
+ touchEvent.preventDefault();
149
+ }
150
+
151
+ emitTouchData(type: string, touches: TouchList) {
152
+ if (!this.videoElementProvider.isVideoReady()) {
153
+ return;
154
+ }
155
+ const offset = this.videoElementProvider.getVideoParentElement().getBoundingClientRect();
156
+ const toStreamerHandlers =
157
+ this.toStreamerMessagesProvider.toStreamerHandlers;
158
+
159
+ for (let t = 0; t < touches.length; t++) {
160
+ const numTouches = 1; // the number of touches to be sent this message
161
+ const touch = touches[t];
162
+ const x = touch.clientX - offset.left;
163
+ const y = touch.clientY - offset.top;
164
+ Logger.Log(
165
+ Logger.GetStackTrace(),
166
+ `F${this.fingerIds.get(touch.identifier)}=(${x}, ${y})`,
167
+ 6
168
+ );
169
+
170
+ const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(
171
+ x,
172
+ y
173
+ );
174
+ switch (type) {
175
+ case 'TouchStart':
176
+ toStreamerHandlers.get('TouchStart')([
177
+ numTouches,
178
+ coord.x,
179
+ coord.y,
180
+ this.fingerIds.get(touch.identifier),
181
+ this.maxByteValue * touch.force,
182
+ coord.inRange ? 1 : 0
183
+ ]);
184
+ break;
185
+ case 'TouchEnd':
186
+ toStreamerHandlers.get('TouchEnd')([
187
+ numTouches,
188
+ coord.x,
189
+ coord.y,
190
+ this.fingerIds.get(touch.identifier),
191
+ this.maxByteValue * touch.force,
192
+ coord.inRange ? 1 : 0
193
+ ]);
194
+ break;
195
+ case 'TouchMove':
196
+ toStreamerHandlers.get('TouchMove')([
197
+ numTouches,
198
+ coord.x,
199
+ coord.y,
200
+ this.fingerIds.get(touch.identifier),
201
+ this.maxByteValue * touch.force,
202
+ coord.inRange ? 1 : 0
203
+ ]);
204
+ break;
205
+ }
206
+ }
207
+ }
208
+ }