@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.1.3 → 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.
- package/.eslintrc.js +1 -1
- package/.prettierrc.json +1 -0
- package/dist/lib-pixelstreamingfrontend.esm.js +1 -1
- package/dist/lib-pixelstreamingfrontend.js +1 -1
- package/package.json +6 -5
- package/src/AFK/AFKController.ts +10 -32
- package/src/Config/Config.ts +179 -201
- package/src/Config/SettingBase.ts +61 -2
- package/src/Config/SettingFlag.ts +10 -48
- package/src/Config/SettingNumber.ts +10 -28
- package/src/Config/SettingOption.ts +13 -46
- package/src/Config/SettingText.ts +9 -37
- package/src/DataChannel/DataChannelController.ts +6 -26
- package/src/DataChannel/DataChannelLatencyTestController.ts +38 -33
- package/src/DataChannel/DataChannelLatencyTestResults.ts +8 -10
- package/src/DataChannel/DataChannelSender.ts +5 -15
- package/src/DataChannel/LatencyTestResults.ts +5 -15
- package/src/FreezeFrame/FreezeFrame.ts +7 -19
- package/src/FreezeFrame/FreezeFrameController.ts +3 -14
- package/src/Inputs/GamepadController.ts +123 -221
- package/src/Inputs/GamepadTypes.ts +23 -0
- package/src/Inputs/IInputController.ts +17 -0
- package/src/Inputs/InputClassesFactory.ts +38 -45
- package/src/Inputs/KeyCodes.ts +114 -0
- package/src/Inputs/KeyboardController.ts +49 -232
- package/src/Inputs/MouseController.ts +71 -297
- package/src/Inputs/MouseControllerHovering.ts +118 -0
- package/src/Inputs/MouseControllerLocked.ts +194 -0
- package/src/Inputs/TouchController.ts +49 -105
- package/src/Inputs/TouchControllerFake.ts +132 -0
- package/src/Inputs/XRGamepadController.ts +35 -44
- package/src/PeerConnectionController/AggregatedStats.ts +26 -54
- package/src/PeerConnectionController/CandidatePairStats.ts +1 -1
- package/src/PeerConnectionController/CandidateStat.ts +1 -1
- package/src/PeerConnectionController/PeerConnectionController.ts +217 -164
- package/src/PixelStreaming/PixelStreaming.ts +174 -226
- package/src/UI/OnScreenKeyboard.ts +14 -9
- package/src/UeInstanceMessage/ResponseController.ts +6 -15
- package/src/UeInstanceMessage/SendMessageController.ts +16 -18
- package/src/UeInstanceMessage/StreamMessageController.ts +3 -12
- package/src/UeInstanceMessage/ToStreamerMessagesController.ts +3 -9
- package/src/Util/EventEmitter.ts +17 -22
- package/src/Util/FileUtil.ts +11 -34
- package/src/Util/IURLSearchParams.ts +25 -0
- package/src/Util/InputCoordTranslator.ts +73 -0
- package/src/Util/RTCUtils.ts +23 -15
- package/src/VideoPlayer/StreamController.ts +6 -23
- package/src/VideoPlayer/VideoPlayer.ts +9 -30
- package/src/WebRtcPlayer/WebRtcPlayerController.ts +328 -690
- package/src/WebXR/WebXRController.ts +82 -94
- package/src/pixelstreamingfrontend.ts +6 -10
- package/types/AFK/AFKController.d.ts +0 -1
- package/types/Config/Config.d.ts +6 -5
- package/types/Config/SettingBase.d.ts +13 -0
- package/types/Config/SettingFlag.d.ts +1 -10
- package/types/Config/SettingNumber.d.ts +1 -5
- package/types/Config/SettingOption.d.ts +1 -10
- package/types/Config/SettingText.d.ts +1 -9
- package/types/DataChannel/DataChannelLatencyTestController.d.ts +1 -1
- package/types/Inputs/GamepadController.d.ts +22 -46
- package/types/Inputs/GamepadTypes.d.ts +7 -0
- package/types/Inputs/IInputController.d.ts +16 -0
- package/types/Inputs/InputClassesFactory.d.ts +7 -8
- package/types/Inputs/KeyCodes.d.ts +5 -0
- package/types/Inputs/KeyboardController.d.ts +17 -45
- package/types/Inputs/MouseController.d.ts +33 -68
- package/types/Inputs/MouseControllerHovering.d.ts +26 -0
- package/types/Inputs/MouseControllerLocked.d.ts +31 -0
- package/types/Inputs/TouchController.d.ts +19 -44
- package/types/Inputs/TouchControllerFake.d.ts +29 -0
- package/types/Inputs/XRGamepadController.d.ts +0 -7
- package/types/PeerConnectionController/PeerConnectionController.d.ts +10 -1
- package/types/PixelStreaming/PixelStreaming.d.ts +14 -2
- package/types/UI/OnScreenKeyboard.d.ts +2 -2
- package/types/Util/EventEmitter.d.ts +1 -1
- package/types/Util/IURLSearchParams.d.ts +9 -0
- package/types/Util/InputCoordTranslator.d.ts +29 -0
- package/types/VideoPlayer/StreamController.d.ts +0 -2
- package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +19 -17
- package/types/pixelstreamingfrontend.d.ts +1 -1
- package/src/Inputs/FakeTouchController.ts +0 -199
- package/src/Inputs/HoveringMouseEvents.ts +0 -192
- package/src/Inputs/IMouseEvents.ts +0 -64
- package/src/Inputs/ITouchController.ts +0 -29
- package/src/Inputs/LockedMouseEvents.ts +0 -287
- package/src/Util/CoordinateConverter.ts +0 -290
- package/src/Util/EventListenerTracker.ts +0 -29
- package/types/Inputs/FakeTouchController.d.ts +0 -61
- package/types/Inputs/HoveringMouseEvents.d.ts +0 -56
- package/types/Inputs/IMouseEvents.d.ts +0 -53
- package/types/Inputs/ITouchController.d.ts +0 -24
- package/types/Inputs/LockedMouseEvents.d.ts +0 -80
- package/types/Util/CoordinateConverter.d.ts +0 -100
- package/types/Util/EventListenerTracker.d.ts +0 -14
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
|
|
2
|
+
import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
|
|
3
|
+
import { InputCoordTranslator, TranslatedCoordUnsigned } from '../Util/InputCoordTranslator';
|
|
4
|
+
import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
|
|
5
|
+
import type { ActiveKeys } from './InputClassesFactory';
|
|
6
|
+
import { MouseController } from './MouseController';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A mouse controller that locks the mouse to the video document and prevents it from leaving the window
|
|
10
|
+
*/
|
|
11
|
+
export class MouseControllerLocked extends MouseController {
|
|
12
|
+
videoElementParent: HTMLDivElement;
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
normalizedCoord: TranslatedCoordUnsigned;
|
|
16
|
+
|
|
17
|
+
// bound listeners
|
|
18
|
+
onRequestLockListener: () => void;
|
|
19
|
+
onLockStateChangeListener: () => void;
|
|
20
|
+
onMouseUpListener: (event: MouseEvent) => void;
|
|
21
|
+
onMouseDownListener: (event: MouseEvent) => void;
|
|
22
|
+
onMouseDblClickListener: (event: MouseEvent) => void;
|
|
23
|
+
onMouseWheelListener: (event: WheelEvent) => void;
|
|
24
|
+
onMouseMoveListener: (event: MouseEvent) => void;
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
streamMessageController: StreamMessageController,
|
|
28
|
+
videoPlayer: VideoPlayer,
|
|
29
|
+
coordinateConverter: InputCoordTranslator,
|
|
30
|
+
activeKeys: ActiveKeys
|
|
31
|
+
) {
|
|
32
|
+
super(streamMessageController, videoPlayer, coordinateConverter, activeKeys);
|
|
33
|
+
this.videoElementParent = videoPlayer.getVideoParentElement() as HTMLDivElement;
|
|
34
|
+
this.x = this.videoElementParent.getBoundingClientRect().width / 2;
|
|
35
|
+
this.y = this.videoElementParent.getBoundingClientRect().height / 2;
|
|
36
|
+
this.normalizedCoord = this.coordinateConverter.translateUnsigned(this.x, this.y);
|
|
37
|
+
|
|
38
|
+
this.onRequestLockListener = this.onRequestLock.bind(this);
|
|
39
|
+
this.onLockStateChangeListener = this.onLockStateChange.bind(this);
|
|
40
|
+
this.onMouseUpListener = this.onMouseUp.bind(this);
|
|
41
|
+
this.onMouseDownListener = this.onMouseDown.bind(this);
|
|
42
|
+
this.onMouseDblClickListener = this.onMouseDblClick.bind(this);
|
|
43
|
+
this.onMouseWheelListener = this.onMouseWheel.bind(this);
|
|
44
|
+
this.onMouseMoveListener = this.onMouseMove.bind(this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
register() {
|
|
48
|
+
super.register();
|
|
49
|
+
|
|
50
|
+
this.videoElementParent.requestPointerLock =
|
|
51
|
+
this.videoElementParent.requestPointerLock || this.videoElementParent.mozRequestPointerLock;
|
|
52
|
+
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
|
|
53
|
+
|
|
54
|
+
if (this.videoElementParent.requestPointerLock) {
|
|
55
|
+
this.videoElementParent.addEventListener('click', this.onRequestLockListener);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
document.addEventListener('pointerlockchange', this.onLockStateChangeListener);
|
|
59
|
+
document.addEventListener('mozpointerlockchange', this.onLockStateChangeListener);
|
|
60
|
+
|
|
61
|
+
this.videoElementParent.addEventListener('mousedown', this.onMouseDownListener);
|
|
62
|
+
this.videoElementParent.addEventListener('mouseup', this.onMouseUpListener);
|
|
63
|
+
this.videoElementParent.addEventListener('wheel', this.onMouseWheelListener);
|
|
64
|
+
this.videoElementParent.addEventListener('dblclick', this.onMouseDblClickListener);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
unregister() {
|
|
68
|
+
const pointerLockElement = document.pointerLockElement || document.mozPointerLockElement;
|
|
69
|
+
if (document.exitPointerLock && pointerLockElement === this.videoElementParent) {
|
|
70
|
+
document.exitPointerLock();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.videoElementParent.removeEventListener('click', this.onRequestLockListener);
|
|
74
|
+
document.removeEventListener('pointerlockchange', this.onLockStateChangeListener);
|
|
75
|
+
document.removeEventListener('mozpointerlockchange', this.onLockStateChangeListener);
|
|
76
|
+
document.removeEventListener('mousemove', this.onMouseMoveListener);
|
|
77
|
+
|
|
78
|
+
this.videoElementParent.removeEventListener('mousedown', this.onMouseDownListener);
|
|
79
|
+
this.videoElementParent.removeEventListener('mouseup', this.onMouseUpListener);
|
|
80
|
+
this.videoElementParent.removeEventListener('wheel', this.onMouseWheelListener);
|
|
81
|
+
this.videoElementParent.removeEventListener('dblclick', this.onMouseDblClickListener);
|
|
82
|
+
|
|
83
|
+
super.unregister();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private onRequestLock() {
|
|
87
|
+
this.videoElementParent.requestPointerLock();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private onLockStateChange() {
|
|
91
|
+
const pointerLockElement = document.pointerLockElement || document.mozPointerLockElement;
|
|
92
|
+
if (pointerLockElement === this.videoElementParent) {
|
|
93
|
+
Logger.Info('Pointer locked');
|
|
94
|
+
document.addEventListener('mousemove', this.onMouseMoveListener);
|
|
95
|
+
} else {
|
|
96
|
+
Logger.Info('The pointer lock status is now unlocked');
|
|
97
|
+
document.removeEventListener('mousemove', this.onMouseMoveListener);
|
|
98
|
+
|
|
99
|
+
// If mouse loses focus, send a key up for all of the currently held-down keys
|
|
100
|
+
// This is necessary as when the mouse loses focus, the windows stops listening for events and as such
|
|
101
|
+
// the keyup listener won't get fired
|
|
102
|
+
const activeKeys = this.activeKeys.getActiveKeys();
|
|
103
|
+
activeKeys.forEach((key: number) => {
|
|
104
|
+
this.streamMessageController.toStreamerHandlers.get('KeyUp')([key]);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private onMouseDown(event: MouseEvent) {
|
|
110
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.streamMessageController.toStreamerHandlers.get('MouseDown')([
|
|
115
|
+
event.button,
|
|
116
|
+
// We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location
|
|
117
|
+
// uses the system cursor location which hasn't moved
|
|
118
|
+
this.normalizedCoord.x,
|
|
119
|
+
this.normalizedCoord.y
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private onMouseUp(event: MouseEvent) {
|
|
124
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.streamMessageController.toStreamerHandlers.get('MouseUp')([
|
|
128
|
+
event.button,
|
|
129
|
+
// We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location
|
|
130
|
+
// uses the system cursor location which hasn't moved
|
|
131
|
+
this.normalizedCoord.x,
|
|
132
|
+
this.normalizedCoord.y
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private onMouseMove(event: MouseEvent) {
|
|
137
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const styleWidth = this.videoPlayer.getVideoParentElement().clientWidth;
|
|
141
|
+
const styleHeight = this.videoPlayer.getVideoParentElement().clientHeight;
|
|
142
|
+
|
|
143
|
+
this.x += event.movementX;
|
|
144
|
+
this.y += event.movementY;
|
|
145
|
+
|
|
146
|
+
while (this.x > styleWidth) {
|
|
147
|
+
this.x -= styleWidth;
|
|
148
|
+
}
|
|
149
|
+
while (this.y > styleHeight) {
|
|
150
|
+
this.y -= styleHeight;
|
|
151
|
+
}
|
|
152
|
+
while (this.x < 0) {
|
|
153
|
+
this.x += styleWidth;
|
|
154
|
+
}
|
|
155
|
+
while (this.y < 0) {
|
|
156
|
+
this.y += styleHeight;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.normalizedCoord = this.coordinateConverter.translateUnsigned(this.x, this.y);
|
|
160
|
+
const delta = this.coordinateConverter.translateSigned(event.movementX, event.movementY);
|
|
161
|
+
this.streamMessageController.toStreamerHandlers.get('MouseMove')([
|
|
162
|
+
this.normalizedCoord.x,
|
|
163
|
+
this.normalizedCoord.y,
|
|
164
|
+
delta.x,
|
|
165
|
+
delta.y
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private onMouseWheel(event: WheelEvent) {
|
|
170
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this.streamMessageController.toStreamerHandlers.get('MouseWheel')([
|
|
174
|
+
event.wheelDelta,
|
|
175
|
+
// We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location
|
|
176
|
+
// uses the system cursor location which hasn't moved
|
|
177
|
+
this.normalizedCoord.x,
|
|
178
|
+
this.normalizedCoord.y
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private onMouseDblClick(event: MouseEvent) {
|
|
183
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
this.streamMessageController.toStreamerHandlers.get('MouseDouble')([
|
|
187
|
+
event.button,
|
|
188
|
+
// We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location
|
|
189
|
+
// uses the system cursor location which hasn't moved
|
|
190
|
+
this.normalizedCoord.x,
|
|
191
|
+
this.normalizedCoord.y
|
|
192
|
+
]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -1,98 +1,65 @@
|
|
|
1
1
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
2
|
|
|
3
3
|
import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
|
|
4
|
-
import {
|
|
4
|
+
import { InputCoordTranslator } from '../Util/InputCoordTranslator';
|
|
5
5
|
import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
|
|
6
6
|
import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import { IInputController } from './IInputController';
|
|
8
|
+
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* The basic touch controller that handles the touch events on the document.
|
|
11
11
|
*/
|
|
12
|
-
export class TouchController implements
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
coordinateConverter:
|
|
12
|
+
export class TouchController implements IInputController {
|
|
13
|
+
streamMessageController: StreamMessageController;
|
|
14
|
+
videoPlayer: VideoPlayer;
|
|
15
|
+
coordinateConverter: InputCoordTranslator;
|
|
16
|
+
|
|
16
17
|
videoElementParent: HTMLVideoElement;
|
|
17
18
|
fingers = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
|
|
18
19
|
fingerIds = new Map();
|
|
19
20
|
maxByteValue = 255;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
onTouchStartListener: (event: TouchEvent) => void;
|
|
23
|
+
onTouchEndListener: (event: TouchEvent) => void;
|
|
24
|
+
onTouchMoveListener: (event: TouchEvent) => void;
|
|
23
25
|
|
|
24
|
-
/**
|
|
25
|
-
* @param toStreamerMessagesProvider - Stream message instance
|
|
26
|
-
* @param videoElementProvider - Video Player instance
|
|
27
|
-
* @param coordinateConverter - A coordinate converter instance
|
|
28
|
-
*/
|
|
29
26
|
constructor(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
coordinateConverter:
|
|
27
|
+
streamMessageController: StreamMessageController,
|
|
28
|
+
videoPlayer: VideoPlayer,
|
|
29
|
+
coordinateConverter: InputCoordTranslator
|
|
33
30
|
) {
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
31
|
+
this.streamMessageController = streamMessageController;
|
|
32
|
+
this.videoPlayer = videoPlayer;
|
|
36
33
|
this.coordinateConverter = coordinateConverter;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
);
|
|
34
|
+
|
|
35
|
+
this.videoElementParent = videoPlayer.getVideoElement();
|
|
36
|
+
|
|
37
|
+
this.onTouchStartListener = this.onTouchStart.bind(this);
|
|
38
|
+
this.onTouchEndListener = this.onTouchEnd.bind(this);
|
|
39
|
+
this.onTouchMoveListener = this.onTouchMove.bind(this);
|
|
66
40
|
}
|
|
67
41
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.touchEventListenerTracker.unregisterAll();
|
|
42
|
+
register() {
|
|
43
|
+
this.videoElementParent.addEventListener('touchstart', this.onTouchStartListener);
|
|
44
|
+
this.videoElementParent.addEventListener('touchend', this.onTouchEndListener);
|
|
45
|
+
this.videoElementParent.addEventListener('touchmove', this.onTouchMoveListener);
|
|
73
46
|
}
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
48
|
+
unregister() {
|
|
49
|
+
this.videoElementParent.addEventListener('touchstart', this.onTouchStartListener);
|
|
50
|
+
this.videoElementParent.addEventListener('touchend', this.onTouchEndListener);
|
|
51
|
+
this.videoElementParent.addEventListener('touchmove', this.onTouchMoveListener);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private rememberTouch(touch: Touch) {
|
|
80
55
|
const finger = this.fingers.pop();
|
|
81
56
|
if (finger === undefined) {
|
|
82
|
-
Logger.
|
|
83
|
-
Logger.GetStackTrace(),
|
|
84
|
-
'exhausted touch identifiers',
|
|
85
|
-
6
|
|
86
|
-
);
|
|
57
|
+
Logger.Info('exhausted touch identifiers');
|
|
87
58
|
}
|
|
88
59
|
this.fingerIds.set(touch.identifier, finger);
|
|
89
60
|
}
|
|
90
61
|
|
|
91
|
-
|
|
92
|
-
* Forgets a touch command
|
|
93
|
-
* @param touch - the touch command
|
|
94
|
-
*/
|
|
95
|
-
forgetTouch(touch: Touch) {
|
|
62
|
+
private forgetTouch(touch: Touch) {
|
|
96
63
|
this.fingers.push(this.fingerIds.get(touch.identifier));
|
|
97
64
|
// 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
65
|
this.fingers.sort(function (a, b) {
|
|
@@ -101,32 +68,22 @@ export class TouchController implements ITouchController {
|
|
|
101
68
|
this.fingerIds.delete(touch.identifier);
|
|
102
69
|
}
|
|
103
70
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
* @param touchEvent - the touch event being intercepted
|
|
107
|
-
*/
|
|
108
|
-
onTouchStart(touchEvent: TouchEvent) {
|
|
109
|
-
if (!this.videoElementProvider.isVideoReady()) {
|
|
71
|
+
private onTouchStart(touchEvent: TouchEvent) {
|
|
72
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
110
73
|
return;
|
|
111
74
|
}
|
|
112
75
|
for (let t = 0; t < touchEvent.changedTouches.length; t++) {
|
|
113
76
|
this.rememberTouch(touchEvent.changedTouches[t]);
|
|
114
77
|
}
|
|
115
|
-
Logger.Log(Logger.GetStackTrace(), 'touch start', 6);
|
|
116
78
|
|
|
117
79
|
this.emitTouchData('TouchStart', touchEvent.changedTouches);
|
|
118
80
|
touchEvent.preventDefault();
|
|
119
81
|
}
|
|
120
82
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* @param touchEvent - the touch event being intercepted
|
|
124
|
-
*/
|
|
125
|
-
onTouchEnd(touchEvent: TouchEvent) {
|
|
126
|
-
if (!this.videoElementProvider.isVideoReady()) {
|
|
83
|
+
private onTouchEnd(touchEvent: TouchEvent) {
|
|
84
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
127
85
|
return;
|
|
128
86
|
}
|
|
129
|
-
Logger.Log(Logger.GetStackTrace(), 'touch end', 6);
|
|
130
87
|
this.emitTouchData('TouchEnd', touchEvent.changedTouches);
|
|
131
88
|
// Re-cycle unique identifiers previously assigned to each touch.
|
|
132
89
|
for (let t = 0; t < touchEvent.changedTouches.length; t++) {
|
|
@@ -135,42 +92,29 @@ export class TouchController implements ITouchController {
|
|
|
135
92
|
touchEvent.preventDefault();
|
|
136
93
|
}
|
|
137
94
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
* @param touchEvent - the touch event being intercepted
|
|
141
|
-
*/
|
|
142
|
-
onTouchMove(touchEvent: TouchEvent) {
|
|
143
|
-
if (!this.videoElementProvider.isVideoReady()) {
|
|
95
|
+
private onTouchMove(touchEvent: TouchEvent) {
|
|
96
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
144
97
|
return;
|
|
145
98
|
}
|
|
146
|
-
Logger.Log(Logger.GetStackTrace(), 'touch move', 6);
|
|
147
99
|
this.emitTouchData('TouchMove', touchEvent.touches);
|
|
148
100
|
touchEvent.preventDefault();
|
|
149
101
|
}
|
|
150
102
|
|
|
151
|
-
emitTouchData(type: string, touches: TouchList) {
|
|
152
|
-
if (!this.
|
|
103
|
+
private emitTouchData(type: string, touches: TouchList) {
|
|
104
|
+
if (!this.videoPlayer.isVideoReady()) {
|
|
153
105
|
return;
|
|
154
106
|
}
|
|
155
|
-
const offset = this.
|
|
156
|
-
const toStreamerHandlers =
|
|
157
|
-
this.toStreamerMessagesProvider.toStreamerHandlers;
|
|
107
|
+
const offset = this.videoPlayer.getVideoParentElement().getBoundingClientRect();
|
|
108
|
+
const toStreamerHandlers = this.streamMessageController.toStreamerHandlers;
|
|
158
109
|
|
|
159
110
|
for (let t = 0; t < touches.length; t++) {
|
|
160
111
|
const numTouches = 1; // the number of touches to be sent this message
|
|
161
112
|
const touch = touches[t];
|
|
162
113
|
const x = touch.clientX - offset.left;
|
|
163
114
|
const y = touch.clientY - offset.top;
|
|
164
|
-
Logger.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
6
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(
|
|
171
|
-
x,
|
|
172
|
-
y
|
|
173
|
-
);
|
|
115
|
+
Logger.Info(`F${this.fingerIds.get(touch.identifier)}=(${x}, ${y})`);
|
|
116
|
+
|
|
117
|
+
const coord = this.coordinateConverter.translateUnsigned(x, y);
|
|
174
118
|
switch (type) {
|
|
175
119
|
case 'TouchStart':
|
|
176
120
|
toStreamerHandlers.get('TouchStart')([
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import { InputCoordTranslator } from '../Util/InputCoordTranslator';
|
|
4
|
+
import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
|
|
5
|
+
import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
|
|
6
|
+
import { MouseButton } from './MouseButtons';
|
|
7
|
+
import { IInputController } from './IInputController';
|
|
8
|
+
|
|
9
|
+
interface FakeTouchFinger {
|
|
10
|
+
id: number;
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Allows for the usage of fake touch events
|
|
17
|
+
*/
|
|
18
|
+
export class TouchControllerFake implements IInputController {
|
|
19
|
+
streamMessageController: StreamMessageController;
|
|
20
|
+
videoPlayer: VideoPlayer;
|
|
21
|
+
coordinateConverter: InputCoordTranslator;
|
|
22
|
+
|
|
23
|
+
fakeTouchFinger: FakeTouchFinger;
|
|
24
|
+
videoElementParentClientRect: DOMRect;
|
|
25
|
+
|
|
26
|
+
onTouchStartListener: (event: TouchEvent) => void;
|
|
27
|
+
onTouchEndListener: (event: TouchEvent) => void;
|
|
28
|
+
onTouchMoveListener: (event: TouchEvent) => void;
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
streamMessageController: StreamMessageController,
|
|
32
|
+
videoPlayer: VideoPlayer,
|
|
33
|
+
coordinateConverter: InputCoordTranslator
|
|
34
|
+
) {
|
|
35
|
+
this.streamMessageController = streamMessageController;
|
|
36
|
+
this.videoPlayer = videoPlayer;
|
|
37
|
+
this.coordinateConverter = coordinateConverter;
|
|
38
|
+
|
|
39
|
+
this.onTouchStartListener = this.onTouchStart.bind(this);
|
|
40
|
+
this.onTouchEndListener = this.onTouchEnd.bind(this);
|
|
41
|
+
this.onTouchMoveListener = this.onTouchMove.bind(this);
|
|
42
|
+
|
|
43
|
+
this.videoElementParentClientRect = this.videoPlayer.getVideoParentElement().getBoundingClientRect();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
register() {
|
|
47
|
+
document.addEventListener('touchstart', this.onTouchStartListener);
|
|
48
|
+
document.addEventListener('touchend', this.onTouchEndListener);
|
|
49
|
+
document.addEventListener('touchmove', this.onTouchMoveListener);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
unregister() {
|
|
53
|
+
document.removeEventListener('touchstart', this.onTouchStartListener);
|
|
54
|
+
document.removeEventListener('touchend', this.onTouchEndListener);
|
|
55
|
+
document.removeEventListener('touchmove', this.onTouchMoveListener);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private onTouchStart(touch: TouchEvent): void {
|
|
59
|
+
if (!this.videoPlayer.isVideoReady() || touch.target !== this.videoPlayer.getVideoElement()) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.fakeTouchFinger == null) {
|
|
63
|
+
const first_touch = touch.changedTouches[0];
|
|
64
|
+
this.fakeTouchFinger = {
|
|
65
|
+
id: first_touch.identifier,
|
|
66
|
+
x: first_touch.clientX - this.videoElementParentClientRect.left,
|
|
67
|
+
y: first_touch.clientY - this.videoElementParentClientRect.top
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const videoElementParent = this.videoPlayer.getVideoParentElement() as HTMLDivElement;
|
|
71
|
+
const mouseEvent = new MouseEvent('mouseenter', first_touch);
|
|
72
|
+
videoElementParent.dispatchEvent(mouseEvent);
|
|
73
|
+
|
|
74
|
+
const coord = this.coordinateConverter.translateUnsigned(
|
|
75
|
+
this.fakeTouchFinger.x,
|
|
76
|
+
this.fakeTouchFinger.y
|
|
77
|
+
);
|
|
78
|
+
const toStreamerHandlers = this.streamMessageController.toStreamerHandlers;
|
|
79
|
+
toStreamerHandlers.get('MouseDown')([MouseButton.mainButton, coord.x, coord.y]);
|
|
80
|
+
}
|
|
81
|
+
touch.preventDefault();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private onTouchEnd(touchEvent: TouchEvent): void {
|
|
85
|
+
if (!this.videoPlayer.isVideoReady() || this.fakeTouchFinger == null) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const videoElementParent = this.videoPlayer.getVideoParentElement();
|
|
89
|
+
const toStreamerHandlers = this.streamMessageController.toStreamerHandlers;
|
|
90
|
+
|
|
91
|
+
for (let t = 0; t < touchEvent.changedTouches.length; t++) {
|
|
92
|
+
const touch = touchEvent.changedTouches[t];
|
|
93
|
+
if (touch.identifier === this.fakeTouchFinger.id) {
|
|
94
|
+
const x = touch.clientX - this.videoElementParentClientRect.left;
|
|
95
|
+
const y = touch.clientY - this.videoElementParentClientRect.top;
|
|
96
|
+
const coord = this.coordinateConverter.translateUnsigned(x, y);
|
|
97
|
+
toStreamerHandlers.get('MouseUp')([MouseButton.mainButton, coord.x, coord.y]);
|
|
98
|
+
|
|
99
|
+
const mouseEvent = new MouseEvent('mouseleave', touch);
|
|
100
|
+
videoElementParent.dispatchEvent(mouseEvent);
|
|
101
|
+
this.fakeTouchFinger = null;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
touchEvent.preventDefault();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private onTouchMove(touchEvent: TouchEvent): void {
|
|
109
|
+
if (!this.videoPlayer.isVideoReady() || this.fakeTouchFinger == null) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const toStreamerHandlers = this.streamMessageController.toStreamerHandlers;
|
|
113
|
+
|
|
114
|
+
for (let t = 0; t < touchEvent.touches.length; t++) {
|
|
115
|
+
const touch = touchEvent.touches[t];
|
|
116
|
+
if (touch.identifier === this.fakeTouchFinger.id) {
|
|
117
|
+
const x = touch.clientX - this.videoElementParentClientRect.left;
|
|
118
|
+
const y = touch.clientY - this.videoElementParentClientRect.top;
|
|
119
|
+
const coord = this.coordinateConverter.translateUnsigned(x, y);
|
|
120
|
+
const delta = this.coordinateConverter.translateSigned(
|
|
121
|
+
x - this.fakeTouchFinger.x,
|
|
122
|
+
y - this.fakeTouchFinger.y
|
|
123
|
+
);
|
|
124
|
+
toStreamerHandlers.get('MouseMove')([coord.x, coord.y, delta.x, delta.y]);
|
|
125
|
+
this.fakeTouchFinger.x = x;
|
|
126
|
+
this.fakeTouchFinger.y = y;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
touchEvent.preventDefault();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
2
|
|
|
3
3
|
import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
|
|
4
|
-
import { Controller } from './GamepadTypes';
|
|
4
|
+
import { Controller, deepCopyGamepad } from './GamepadTypes';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The class that handles the functionality of XR gamepads and controllers.
|
|
@@ -18,34 +18,7 @@ export class XRGamepadController {
|
|
|
18
18
|
this.controllers = [];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
* Deep copies the values from a gamepad by first converting it to a JSON object and then back to a gamepad
|
|
23
|
-
*
|
|
24
|
-
* @param gamepad the original gamepad
|
|
25
|
-
* @returns a new gamepad object, populated with the original gamepads values
|
|
26
|
-
*/
|
|
27
|
-
static deepCopyGamepad(gamepad: Gamepad): Gamepad {
|
|
28
|
-
return JSON.parse(
|
|
29
|
-
JSON.stringify({
|
|
30
|
-
buttons: gamepad.buttons.map((b) =>
|
|
31
|
-
JSON.parse(
|
|
32
|
-
JSON.stringify({
|
|
33
|
-
pressed: b.pressed,
|
|
34
|
-
touched: b.touched,
|
|
35
|
-
value: b.value
|
|
36
|
-
})
|
|
37
|
-
)
|
|
38
|
-
),
|
|
39
|
-
axes: gamepad.axes
|
|
40
|
-
})
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
updateStatus(
|
|
45
|
-
source: XRInputSource,
|
|
46
|
-
frame: XRFrame,
|
|
47
|
-
refSpace: XRReferenceSpace
|
|
48
|
-
) {
|
|
21
|
+
updateStatus(source: XRInputSource, frame: XRFrame, refSpace: XRReferenceSpace) {
|
|
49
22
|
if (source.gamepad) {
|
|
50
23
|
const gamepadPose = frame.getPose(source.gripSpace, refSpace);
|
|
51
24
|
if (!gamepadPose) {
|
|
@@ -59,9 +32,7 @@ export class XRGamepadController {
|
|
|
59
32
|
system = 2;
|
|
60
33
|
}
|
|
61
34
|
// TODO (william.belcher): Add other profiles (Quest, Microsoft Mixed Reality, etc)
|
|
62
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRSystem')([
|
|
63
|
-
system
|
|
64
|
-
]);
|
|
35
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRSystem')([system]);
|
|
65
36
|
|
|
66
37
|
// Default: AnyHand (2)
|
|
67
38
|
let handedness = 2;
|
|
@@ -95,12 +66,12 @@ export class XRGamepadController {
|
|
|
95
66
|
this.controllers[handedness] = {
|
|
96
67
|
prevState: undefined,
|
|
97
68
|
currentState: undefined,
|
|
98
|
-
|
|
69
|
+
id: undefined
|
|
99
70
|
};
|
|
100
|
-
this.controllers[handedness].prevState =
|
|
71
|
+
this.controllers[handedness].prevState = deepCopyGamepad(source.gamepad);
|
|
101
72
|
}
|
|
102
73
|
|
|
103
|
-
this.controllers[handedness].currentState =
|
|
74
|
+
this.controllers[handedness].currentState = deepCopyGamepad(source.gamepad);
|
|
104
75
|
|
|
105
76
|
const controller = this.controllers[handedness];
|
|
106
77
|
const currState = controller.currentState;
|
|
@@ -113,18 +84,34 @@ export class XRGamepadController {
|
|
|
113
84
|
if (currButton.pressed) {
|
|
114
85
|
// press
|
|
115
86
|
const isRepeat = prevButton.pressed ? 1 : 0;
|
|
116
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonPressed')([
|
|
87
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonPressed')([
|
|
88
|
+
handedness,
|
|
89
|
+
i,
|
|
90
|
+
isRepeat,
|
|
91
|
+
currButton.value
|
|
92
|
+
]);
|
|
117
93
|
} else if (prevButton.pressed) {
|
|
118
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonReleased')([
|
|
94
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonReleased')([
|
|
95
|
+
handedness,
|
|
96
|
+
i,
|
|
97
|
+
0
|
|
98
|
+
]);
|
|
119
99
|
}
|
|
120
100
|
|
|
121
101
|
if (currButton.touched) {
|
|
122
102
|
// touched
|
|
123
103
|
const isRepeat = prevButton.touched ? 1 : 0;
|
|
124
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonTouched')([
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
104
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonTouched')([
|
|
105
|
+
handedness,
|
|
106
|
+
i,
|
|
107
|
+
isRepeat
|
|
108
|
+
]);
|
|
109
|
+
} else if (prevButton.touched) {
|
|
110
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonTouchReleased')([
|
|
111
|
+
handedness,
|
|
112
|
+
i,
|
|
113
|
+
0
|
|
114
|
+
]);
|
|
128
115
|
}
|
|
129
116
|
}
|
|
130
117
|
|
|
@@ -133,12 +120,16 @@ export class XRGamepadController {
|
|
|
133
120
|
const curAxisValue = currState.axes[i];
|
|
134
121
|
const prevAxisValue = prevState.axes[i];
|
|
135
122
|
// Only send axis update if there is a change
|
|
136
|
-
if(curAxisValue != prevAxisValue) {
|
|
137
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRAnalog')([
|
|
123
|
+
if (curAxisValue != prevAxisValue) {
|
|
124
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRAnalog')([
|
|
125
|
+
handedness,
|
|
126
|
+
i,
|
|
127
|
+
curAxisValue
|
|
128
|
+
]);
|
|
138
129
|
}
|
|
139
130
|
}
|
|
140
131
|
|
|
141
132
|
this.controllers[handedness].prevState = currState;
|
|
142
133
|
}
|
|
143
134
|
}
|
|
144
|
-
}
|
|
135
|
+
}
|