@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.
- package/.cspell.json +48 -0
- package/.eslintignore +8 -0
- package/.eslintrc.js +8 -0
- package/.prettierignore +0 -0
- package/.prettierrc.json +6 -0
- package/dist/lib-pixelstreamingfrontend.esm.js +1 -0
- package/dist/lib-pixelstreamingfrontend.js +1 -0
- package/jest.config.js +18 -0
- package/package.json +48 -0
- package/readme.md +15 -0
- package/src/AFK/AFKController.test.ts +162 -0
- package/src/AFK/AFKController.ts +158 -0
- package/src/Config/Config.test.ts +222 -0
- package/src/Config/Config.ts +970 -0
- package/src/Config/SettingBase.ts +65 -0
- package/src/Config/SettingFlag.ts +99 -0
- package/src/Config/SettingNumber.ts +111 -0
- package/src/Config/SettingOption.ts +124 -0
- package/src/Config/SettingText.ts +82 -0
- package/src/DataChannel/DataChannelController.ts +138 -0
- package/src/DataChannel/DataChannelLatencyTestController.ts +129 -0
- package/src/DataChannel/DataChannelLatencyTestResults.ts +67 -0
- package/src/DataChannel/DataChannelSender.ts +59 -0
- package/src/DataChannel/InitialSettings.ts +61 -0
- package/src/DataChannel/LatencyTestResults.ts +76 -0
- package/src/FreezeFrame/FreezeFrame.ts +114 -0
- package/src/FreezeFrame/FreezeFrameController.ts +114 -0
- package/src/Inputs/FakeTouchController.ts +199 -0
- package/src/Inputs/GamepadController.ts +314 -0
- package/src/Inputs/GamepadTypes.ts +10 -0
- package/src/Inputs/HoveringMouseEvents.ts +192 -0
- package/src/Inputs/IMouseEvents.ts +64 -0
- package/src/Inputs/ITouchController.ts +29 -0
- package/src/Inputs/InputClassesFactory.ts +140 -0
- package/src/Inputs/KeyboardController.ts +354 -0
- package/src/Inputs/LockedMouseEvents.ts +287 -0
- package/src/Inputs/MouseButtons.ts +25 -0
- package/src/Inputs/MouseController.ts +362 -0
- package/src/Inputs/SpecialKeyCodes.ts +16 -0
- package/src/Inputs/TouchController.ts +208 -0
- package/src/Inputs/XRGamepadController.ts +126 -0
- package/src/PeerConnectionController/AggregatedStats.ts +311 -0
- package/src/PeerConnectionController/CandidatePairStats.ts +17 -0
- package/src/PeerConnectionController/CandidateStat.ts +13 -0
- package/src/PeerConnectionController/CodecStats.ts +19 -0
- package/src/PeerConnectionController/DataChannelStats.ts +17 -0
- package/src/PeerConnectionController/InboundRTPStats.ts +154 -0
- package/src/PeerConnectionController/InboundTrackStats.ts +34 -0
- package/src/PeerConnectionController/OutBoundRTPStats.ts +26 -0
- package/src/PeerConnectionController/PeerConnectionController.ts +563 -0
- package/src/PeerConnectionController/SessionStats.ts +10 -0
- package/src/PeerConnectionController/StreamStats.ts +11 -0
- package/src/PixelStreaming/PixelStreaming.test.ts +626 -0
- package/src/PixelStreaming/PixelStreaming.ts +851 -0
- package/src/UI/OnScreenKeyboard.ts +97 -0
- package/src/UeInstanceMessage/ResponseController.ts +47 -0
- package/src/UeInstanceMessage/SendMessageController.ts +154 -0
- package/src/UeInstanceMessage/StreamMessageController.ts +233 -0
- package/src/UeInstanceMessage/ToStreamerMessagesController.ts +62 -0
- package/src/Util/CoordinateConverter.ts +289 -0
- package/src/Util/EventEmitter.ts +611 -0
- package/src/Util/EventListenerTracker.ts +29 -0
- package/src/Util/FileUtil.ts +140 -0
- package/src/Util/RTCUtils.ts +41 -0
- package/src/Util/WebGLUtils.ts +49 -0
- package/src/Util/WebXRUtils.ts +25 -0
- package/src/VideoPlayer/StreamController.ts +89 -0
- package/src/VideoPlayer/VideoPlayer.ts +246 -0
- package/src/WebRtcPlayer/WebRtcPlayerController.ts +2158 -0
- package/src/WebXR/WebXRController.ts +319 -0
- package/src/__test__/mockMediaStream.ts +124 -0
- package/src/__test__/mockRTCPeerConnection.ts +347 -0
- package/src/__test__/mockRTCRtpReceiver.ts +22 -0
- package/src/__test__/mockWebSocket.ts +136 -0
- package/src/pixelstreamingfrontend.ts +46 -0
- package/tsconfig.jest.json +8 -0
- package/tsconfig.json +24 -0
- package/types/AFK/AFKController.d.ts +39 -0
- package/types/Config/Config.d.ts +218 -0
- package/types/Config/SettingBase.d.ts +30 -0
- package/types/Config/SettingFlag.d.ts +33 -0
- package/types/Config/SettingNumber.d.ts +45 -0
- package/types/Config/SettingOption.d.ts +43 -0
- package/types/Config/SettingText.d.ts +29 -0
- package/types/DataChannel/DataChannelController.d.ts +59 -0
- package/types/DataChannel/DataChannelLatencyTestController.d.ts +26 -0
- package/types/DataChannel/DataChannelLatencyTestResults.d.ts +46 -0
- package/types/DataChannel/DataChannelSender.d.ts +21 -0
- package/types/DataChannel/InitialSettings.d.ts +44 -0
- package/types/DataChannel/LatencyTestResults.d.ts +31 -0
- package/types/FreezeFrame/FreezeFrame.d.ts +36 -0
- package/types/FreezeFrame/FreezeFrameController.d.ts +37 -0
- package/types/Inputs/FakeTouchController.d.ts +61 -0
- package/types/Inputs/GamepadController.d.ts +85 -0
- package/types/Inputs/GamepadTypes.d.ts +8 -0
- package/types/Inputs/HoveringMouseEvents.d.ts +56 -0
- package/types/Inputs/IMouseEvents.d.ts +53 -0
- package/types/Inputs/ITouchController.d.ts +24 -0
- package/types/Inputs/InputClassesFactory.d.ts +54 -0
- package/types/Inputs/KeyboardController.d.ts +62 -0
- package/types/Inputs/LockedMouseEvents.d.ts +80 -0
- package/types/Inputs/MouseButtons.d.ts +22 -0
- package/types/Inputs/MouseController.d.ts +75 -0
- package/types/Inputs/SpecialKeyCodes.d.ts +14 -0
- package/types/Inputs/TouchController.d.ts +53 -0
- package/types/Inputs/XRGamepadController.d.ts +15 -0
- package/types/PeerConnectionController/AggregatedStats.d.ts +77 -0
- package/types/PeerConnectionController/CandidatePairStats.d.ts +15 -0
- package/types/PeerConnectionController/CandidateStat.d.ts +11 -0
- package/types/PeerConnectionController/CodecStats.d.ts +14 -0
- package/types/PeerConnectionController/DataChannelStats.d.ts +15 -0
- package/types/PeerConnectionController/InboundRTPStats.d.ts +141 -0
- package/types/PeerConnectionController/InboundTrackStats.d.ts +32 -0
- package/types/PeerConnectionController/OutBoundRTPStats.d.ts +23 -0
- package/types/PeerConnectionController/PeerConnectionController.d.ts +132 -0
- package/types/PeerConnectionController/SessionStats.d.ts +8 -0
- package/types/PeerConnectionController/StreamStats.d.ts +9 -0
- package/types/PixelStreaming/PixelStreaming.d.ts +259 -0
- package/types/UI/OnScreenKeyboard.d.ts +31 -0
- package/types/UeInstanceMessage/ResponseController.d.ts +19 -0
- package/types/UeInstanceMessage/SendMessageController.d.ts +18 -0
- package/types/UeInstanceMessage/StreamMessageController.d.ts +29 -0
- package/types/UeInstanceMessage/ToStreamerMessagesController.d.ts +32 -0
- package/types/Util/CoordinateConverter.d.ts +100 -0
- package/types/Util/EventEmitter.d.ts +422 -0
- package/types/Util/EventListenerTracker.d.ts +14 -0
- package/types/Util/FileUtil.d.ts +32 -0
- package/types/Util/RTCUtils.d.ts +8 -0
- package/types/Util/WebGLUtils.d.ts +4 -0
- package/types/Util/WebXRUtils.d.ts +9 -0
- package/types/VideoPlayer/StreamController.d.ts +24 -0
- package/types/VideoPlayer/VideoPlayer.d.ts +78 -0
- package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +377 -0
- package/types/WebXR/WebXRController.d.ts +26 -0
- package/types/pixelstreamingfrontend.d.ts +22 -0
- package/webpack.common.js +35 -0
- package/webpack.dev.js +35 -0
- 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
|
+
}
|