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