@3dsource/angular-unreal-module 0.0.132 → 0.0.134
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.
|
@@ -807,9 +807,12 @@ function OnOpenHandler() {
|
|
|
807
807
|
*/
|
|
808
808
|
const keepMaxUntilReset = (reset$) => (source$) => merge(source$, reset$.pipe(map(() => null))).pipe(scan((max, value) => (value === null ? 0 : Math.max(max, value)), 0));
|
|
809
809
|
|
|
810
|
+
// Reused across every inbound data-channel message — instantiating a
|
|
811
|
+
// TextDecoder per call adds needless GC churn on a hot path.
|
|
812
|
+
const utf16Decoder = new TextDecoder('utf-16');
|
|
810
813
|
function decodeData(anyData) {
|
|
811
814
|
try {
|
|
812
|
-
return
|
|
815
|
+
return utf16Decoder.decode(anyData);
|
|
813
816
|
}
|
|
814
817
|
catch {
|
|
815
818
|
return '';
|
|
@@ -874,7 +877,6 @@ class DataFlowMonitor {
|
|
|
874
877
|
},
|
|
875
878
|
isDropDetected: true,
|
|
876
879
|
dropPercentage,
|
|
877
|
-
dataHistory: [...this.dataHistory],
|
|
878
880
|
activeMedian: secondHalfMedian,
|
|
879
881
|
quality: isRedFlag ? 'red' : 'orange',
|
|
880
882
|
message: `Significant flow drop detected: ${dropPercentage.toFixed(2)}% (from ${firstHalfMedian} to ${secondHalfMedian})`,
|
|
@@ -889,7 +891,6 @@ class DataFlowMonitor {
|
|
|
889
891
|
},
|
|
890
892
|
isDropDetected: false,
|
|
891
893
|
dropPercentage,
|
|
892
|
-
dataHistory: [...this.dataHistory],
|
|
893
894
|
activeMedian: secondHalfMedian,
|
|
894
895
|
quality: 'lime',
|
|
895
896
|
message: 'Stable flow',
|
|
@@ -1071,6 +1072,28 @@ function qpToQuality(VideoEncoderQP) {
|
|
|
1071
1072
|
return quality;
|
|
1072
1073
|
}
|
|
1073
1074
|
|
|
1075
|
+
/**
|
|
1076
|
+
* Base64-encodes a byte array.
|
|
1077
|
+
*
|
|
1078
|
+
* Builds the intermediate binary string in fixed-size chunks instead of
|
|
1079
|
+
* concatenating one character at a time. The naive `bytes.reduce((s, b) => s +
|
|
1080
|
+
* String.fromCharCode(b), '')` is O(n²) (each `+` re-copies the growing string)
|
|
1081
|
+
* and stalls the main thread for a full-resolution frame; chunking keeps it
|
|
1082
|
+
* O(n). The chunk size stays under the argument-count limit of
|
|
1083
|
+
* `String.fromCharCode.apply`/spread.
|
|
1084
|
+
*
|
|
1085
|
+
* @param bytes - The raw bytes to encode.
|
|
1086
|
+
* @returns The Base64 representation of `bytes`.
|
|
1087
|
+
*/
|
|
1088
|
+
function uint8ToBase64(bytes) {
|
|
1089
|
+
const CHUNK_SIZE = 0x8000;
|
|
1090
|
+
let binary = '';
|
|
1091
|
+
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
|
1092
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
|
|
1093
|
+
}
|
|
1094
|
+
return btoa(binary);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1074
1097
|
function fromResizeObserver(elem) {
|
|
1075
1098
|
return new Observable((subscriber) => {
|
|
1076
1099
|
const observer = new window.ResizeObserver((entries) => subscriber.next(entries));
|
|
@@ -2233,7 +2256,11 @@ class SignallingService extends SubService {
|
|
|
2233
2256
|
dataString = JSON.stringify(data);
|
|
2234
2257
|
}
|
|
2235
2258
|
if (this.ws && this.ws.readyState === WS_OPEN_STATE) {
|
|
2236
|
-
|
|
2259
|
+
// Only parse-for-display when the logger would actually print — avoids a
|
|
2260
|
+
// JSON.parse on every outbound message in production (logger is a no-op).
|
|
2261
|
+
if (Logger.isDevMode) {
|
|
2262
|
+
Logger.colored(...COLOR_CODES.TO_CIRRUS, JSON.parse(dataString));
|
|
2263
|
+
}
|
|
2237
2264
|
try {
|
|
2238
2265
|
this.ws.send(dataString);
|
|
2239
2266
|
}
|
|
@@ -2426,7 +2453,7 @@ class VideoService extends SubService {
|
|
|
2426
2453
|
this.latencyTestTimings.SetUETimings(latencyTimings);
|
|
2427
2454
|
}
|
|
2428
2455
|
setEncoder(data) {
|
|
2429
|
-
this.VideoEncoderQP = Number(
|
|
2456
|
+
this.VideoEncoderQP = Number(decodeData(data));
|
|
2430
2457
|
}
|
|
2431
2458
|
create() {
|
|
2432
2459
|
if (!this.container) {
|
|
@@ -4064,7 +4091,7 @@ class FreezeFrameService extends SubService {
|
|
|
4064
4091
|
if (!this.jpeg) {
|
|
4065
4092
|
return;
|
|
4066
4093
|
}
|
|
4067
|
-
const base64 =
|
|
4094
|
+
const base64 = uint8ToBase64(this.jpeg);
|
|
4068
4095
|
this.freezeFrameOverlay.src = 'data:image/jpeg;base64,' + base64;
|
|
4069
4096
|
this.store.dispatch(setFreezeFrame({
|
|
4070
4097
|
dataUrl: this.freezeFrameOverlay.src,
|
|
@@ -4162,7 +4189,7 @@ class FileReceiverService extends SubService {
|
|
|
4162
4189
|
this.resetOnStart();
|
|
4163
4190
|
}
|
|
4164
4191
|
//Logger.info(extensionAsString);
|
|
4165
|
-
this.extension =
|
|
4192
|
+
this.extension = decodeData(view.slice(1).buffer);
|
|
4166
4193
|
}
|
|
4167
4194
|
/**
|
|
4168
4195
|
* Processes a file mime type when received over data channel
|
|
@@ -4173,7 +4200,7 @@ class FileReceiverService extends SubService {
|
|
|
4173
4200
|
if (!this.receiving) {
|
|
4174
4201
|
this.resetOnStart();
|
|
4175
4202
|
}
|
|
4176
|
-
const mimeAsString =
|
|
4203
|
+
const mimeAsString = decodeData(view.slice(1).buffer);
|
|
4177
4204
|
// Logger.info(mimeAsString);
|
|
4178
4205
|
this.mimetype = mimeAsString;
|
|
4179
4206
|
}
|
|
@@ -4353,8 +4380,10 @@ class AggregatorService extends SubService {
|
|
|
4353
4380
|
break;
|
|
4354
4381
|
}
|
|
4355
4382
|
case ToClientMessage.Command: {
|
|
4356
|
-
|
|
4357
|
-
Logger.
|
|
4383
|
+
// The parsed command is only used for the dev log — skip the work in prod.
|
|
4384
|
+
if (Logger.isDevMode) {
|
|
4385
|
+
Logger.colored(...COLOR_CODES.FROM_UNREAL, JSON.parse(decodeData(anyData)));
|
|
4386
|
+
}
|
|
4358
4387
|
break;
|
|
4359
4388
|
}
|
|
4360
4389
|
case ToClientMessage.FileExtension:
|
|
@@ -4388,10 +4417,14 @@ class AggregatorService extends SubService {
|
|
|
4388
4417
|
break;
|
|
4389
4418
|
}
|
|
4390
4419
|
case ToClientMessage.InitialSettings:
|
|
4391
|
-
Logger.
|
|
4420
|
+
if (Logger.isDevMode) {
|
|
4421
|
+
Logger.colored(...COLOR_CODES.FROM_UNREAL, 'InitialSettings message :', JSON.parse(decodeData(anyData)));
|
|
4422
|
+
}
|
|
4392
4423
|
break;
|
|
4393
4424
|
case ToClientMessage.Protocol:
|
|
4394
|
-
Logger.
|
|
4425
|
+
if (Logger.isDevMode) {
|
|
4426
|
+
Logger.colored(...COLOR_CODES.FROM_UNREAL, 'Protocol message :', JSON.parse(decodeData(anyData)));
|
|
4427
|
+
}
|
|
4395
4428
|
break;
|
|
4396
4429
|
case ToClientMessage.InputControlOwnership:
|
|
4397
4430
|
Logger.colored(...COLOR_CODES.FROM_UNREAL, 'InputControlOwnership message :', anyData);
|
|
@@ -4493,6 +4526,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
4493
4526
|
}], ctorParameters: () => [] });
|
|
4494
4527
|
|
|
4495
4528
|
const INITIAL_FINGER_IDS = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
|
|
4529
|
+
const UNSIGNED_RANGE = 65536;
|
|
4530
|
+
const UNSIGNED_OUT_OF_RANGE = 65535;
|
|
4531
|
+
const SIGNED_RANGE = 32767;
|
|
4532
|
+
const WHEEL_DELTA_SCALE = -120;
|
|
4533
|
+
const RESIZE_DEBOUNCE_MS = 300;
|
|
4534
|
+
const FUNCTION_KEY_MIN = 112;
|
|
4535
|
+
const FUNCTION_KEY_MAX = 123;
|
|
4536
|
+
const TAB_KEY_CODE = 9;
|
|
4496
4537
|
class InputService extends SubService {
|
|
4497
4538
|
constructor() {
|
|
4498
4539
|
super();
|
|
@@ -4522,19 +4563,25 @@ class InputService extends SubService {
|
|
|
4522
4563
|
this.deactivatedVideoTrigger$ = NEVER;
|
|
4523
4564
|
this.normalizeAndQuantizeUnsigned = (_x, _y) => ({
|
|
4524
4565
|
inRange: false,
|
|
4525
|
-
x:
|
|
4526
|
-
y:
|
|
4566
|
+
x: UNSIGNED_OUT_OF_RANGE,
|
|
4567
|
+
y: UNSIGNED_OUT_OF_RANGE,
|
|
4527
4568
|
});
|
|
4528
4569
|
this.normalizeAndQuantizeSigned = (_x, _y) => ({ x: 0, y: 0 });
|
|
4529
4570
|
this.videoBoundingRect = new DOMRect(0, 0, 1, 1);
|
|
4530
4571
|
this.fingerIds = new Map();
|
|
4531
4572
|
this.maxByteValue = 255;
|
|
4532
4573
|
this.fingers = [...INITIAL_FINGER_IDS];
|
|
4533
|
-
//
|
|
4534
|
-
//
|
|
4535
|
-
//
|
|
4536
|
-
|
|
4537
|
-
this.
|
|
4574
|
+
// Reusable wire buffers. Input events fire at up to ~60 Hz; the data channel
|
|
4575
|
+
// copies the bytes synchronously on send (RTCDataChannel.send), so a single
|
|
4576
|
+
// buffer per message shape is safe and avoids per-event allocation/GC churn.
|
|
4577
|
+
this.mouseMoveView = new DataView(new ArrayBuffer(9));
|
|
4578
|
+
this.mouseButtonView = new DataView(new ArrayBuffer(6));
|
|
4579
|
+
this.mouseWheelView = new DataView(new ArrayBuffer(7));
|
|
4580
|
+
this.touchView = new DataView(new ArrayBuffer(9));
|
|
4581
|
+
this.keyPressView = new DataView(new ArrayBuffer(3));
|
|
4582
|
+
this.singleByteView = new DataView(new ArrayBuffer(1));
|
|
4583
|
+
this.keyDownBytes = new Uint8Array(3);
|
|
4584
|
+
this.keyUpBytes = new Uint8Array(2);
|
|
4538
4585
|
this.offsetParams = {
|
|
4539
4586
|
scaleX: 1,
|
|
4540
4587
|
scaleY: 1,
|
|
@@ -4573,26 +4620,11 @@ class InputService extends SubService {
|
|
|
4573
4620
|
this.fingerIds.clear();
|
|
4574
4621
|
this.fingers = [...INITIAL_FINGER_IDS];
|
|
4575
4622
|
merge(fromResizeObserver(video), this.actions$.pipe(ofType(videoAdaptedToContainer)))
|
|
4576
|
-
.pipe(debounceTime$1(
|
|
4577
|
-
.subscribe(() =>
|
|
4578
|
-
this.setupNormalizeAndQuantize(video);
|
|
4579
|
-
this.resendLastMousePosition();
|
|
4580
|
-
});
|
|
4623
|
+
.pipe(debounceTime$1(RESIZE_DEBOUNCE_MS), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4624
|
+
.subscribe(() => this.setupNormalizeAndQuantize(video));
|
|
4581
4625
|
this.setupNormalizeAndQuantize(video);
|
|
4582
4626
|
this.registerInputs(video);
|
|
4583
4627
|
}
|
|
4584
|
-
resendLastMousePosition() {
|
|
4585
|
-
const last = this.lastNormalizedCoordinates;
|
|
4586
|
-
if (!last)
|
|
4587
|
-
return;
|
|
4588
|
-
const data = new DataView(new ArrayBuffer(9));
|
|
4589
|
-
data.setUint8(0, MessageType.MouseMove);
|
|
4590
|
-
data.setUint16(1, last.x, true);
|
|
4591
|
-
data.setUint16(3, last.y, true);
|
|
4592
|
-
data.setInt16(5, 0, true);
|
|
4593
|
-
data.setInt16(7, 0, true);
|
|
4594
|
-
this.sendInputData(data.buffer);
|
|
4595
|
-
}
|
|
4596
4628
|
/**
|
|
4597
4629
|
* We use `object-fit: cover` on the video element. Since the video can have
|
|
4598
4630
|
* a different aspect ratio from its container (and potentially be larger),
|
|
@@ -4610,18 +4642,13 @@ class InputService extends SubService {
|
|
|
4610
4642
|
videoWidth,
|
|
4611
4643
|
videoHeight,
|
|
4612
4644
|
});
|
|
4613
|
-
// Compute aspect ratios
|
|
4614
4645
|
const containerRatio = width / height;
|
|
4615
4646
|
const videoRatio = videoWidth / videoHeight;
|
|
4616
|
-
// Determine how much to scale the video to fit the container (cover mode)
|
|
4617
4647
|
const scale = videoRatio > containerRatio ? height / videoHeight : width / videoWidth;
|
|
4618
|
-
// Calculate the displayed (scaled) dimensions of the video
|
|
4619
4648
|
const scaledWidth = videoWidth * scale;
|
|
4620
4649
|
const scaledHeight = videoHeight * scale;
|
|
4621
|
-
// Offsets in x/y directions (like "padding") once the video is scaled
|
|
4622
4650
|
const offsetByX = (width - scaledWidth) / 2;
|
|
4623
4651
|
const offsetByY = (height - scaledHeight) / 2;
|
|
4624
|
-
// Scale factors for coordinate transformation from container space to video space
|
|
4625
4652
|
const scaleX = width / scaledWidth;
|
|
4626
4653
|
const scaleY = height / scaledHeight;
|
|
4627
4654
|
return {
|
|
@@ -4637,14 +4664,13 @@ class InputService extends SubService {
|
|
|
4637
4664
|
this.videoBoundingRect = videoElement.getBoundingClientRect();
|
|
4638
4665
|
this.offsetParams = this.getObjectFitOffset(videoElement);
|
|
4639
4666
|
// Unsigned XY positions are the ratio (0.0..1.0) along a viewport axis,
|
|
4640
|
-
// quantized into
|
|
4667
|
+
// quantized into a uint16 (0..65536).
|
|
4641
4668
|
// Signed XY deltas are the ratio (-1.0..1.0) along a viewport axis,
|
|
4642
4669
|
// quantized into an int16 (-32767..32767).
|
|
4643
|
-
// This allows the browser viewport and client viewport to have
|
|
4644
|
-
//
|
|
4645
|
-
//
|
|
4646
|
-
//
|
|
4647
|
-
// precisely inside a video with an aspect ratio which causes mattes.
|
|
4670
|
+
// This allows the browser viewport and client viewport to have different sizes.
|
|
4671
|
+
// Hack: an out-of-range position becomes UNSIGNED_OUT_OF_RANGE because we
|
|
4672
|
+
// can't yet accurately detect mouse enter/leave precisely inside a video
|
|
4673
|
+
// with an aspect ratio that causes mattes.
|
|
4648
4674
|
this.normalizeAndQuantizeUnsigned = (x, y) => {
|
|
4649
4675
|
const normalizedX = x / videoElement.clientWidth;
|
|
4650
4676
|
const normalizedY = y / videoElement.clientHeight;
|
|
@@ -4654,25 +4680,22 @@ class InputService extends SubService {
|
|
|
4654
4680
|
normalizedY > 1.0) {
|
|
4655
4681
|
return {
|
|
4656
4682
|
inRange: false,
|
|
4657
|
-
x:
|
|
4658
|
-
y:
|
|
4659
|
-
};
|
|
4660
|
-
}
|
|
4661
|
-
else {
|
|
4662
|
-
return {
|
|
4663
|
-
inRange: true,
|
|
4664
|
-
x: normalizedX * 65536,
|
|
4665
|
-
y: normalizedY * 65536,
|
|
4683
|
+
x: UNSIGNED_OUT_OF_RANGE,
|
|
4684
|
+
y: UNSIGNED_OUT_OF_RANGE,
|
|
4666
4685
|
};
|
|
4667
4686
|
}
|
|
4687
|
+
return {
|
|
4688
|
+
inRange: true,
|
|
4689
|
+
x: normalizedX * UNSIGNED_RANGE,
|
|
4690
|
+
y: normalizedY * UNSIGNED_RANGE,
|
|
4691
|
+
};
|
|
4668
4692
|
};
|
|
4669
|
-
// Signed.
|
|
4670
4693
|
this.normalizeAndQuantizeSigned = (x, y) => {
|
|
4671
4694
|
const normalizedX = x / (0.5 * videoElement.clientWidth);
|
|
4672
4695
|
const normalizedY = y / (0.5 * videoElement.clientHeight);
|
|
4673
4696
|
return {
|
|
4674
|
-
x: normalizedX *
|
|
4675
|
-
y: normalizedY *
|
|
4697
|
+
x: normalizedX * SIGNED_RANGE,
|
|
4698
|
+
y: normalizedY * SIGNED_RANGE,
|
|
4676
4699
|
};
|
|
4677
4700
|
};
|
|
4678
4701
|
}
|
|
@@ -4695,7 +4718,7 @@ class InputService extends SubService {
|
|
|
4695
4718
|
y: (clientY - offsetByY - this.videoBoundingRect.top) * scaleY,
|
|
4696
4719
|
};
|
|
4697
4720
|
}
|
|
4698
|
-
getMousePositionWithOffset({ offsetX, offsetY
|
|
4721
|
+
getMousePositionWithOffset({ offsetX, offsetY }) {
|
|
4699
4722
|
const { offsetByX, offsetByY, scaleX, scaleY } = this.offsetParams;
|
|
4700
4723
|
return {
|
|
4701
4724
|
x: (offsetX - offsetByX) * scaleX,
|
|
@@ -4703,8 +4726,6 @@ class InputService extends SubService {
|
|
|
4703
4726
|
};
|
|
4704
4727
|
}
|
|
4705
4728
|
registerTouchEvents(htmlVideoElement) {
|
|
4706
|
-
// We need to assign a unique identifier to each finger.
|
|
4707
|
-
// We do this by mapping each Touch object to the identifier.
|
|
4708
4729
|
const rememberTouch = (touch) => {
|
|
4709
4730
|
const finger = this.fingers.pop();
|
|
4710
4731
|
if (finger === undefined) {
|
|
@@ -4715,39 +4736,41 @@ class InputService extends SubService {
|
|
|
4715
4736
|
};
|
|
4716
4737
|
const forgetTouch = (touch) => {
|
|
4717
4738
|
const finger = this.fingerIds.get(touch.identifier);
|
|
4718
|
-
if (finger) {
|
|
4739
|
+
if (finger !== undefined) {
|
|
4719
4740
|
this.fingers.push(finger);
|
|
4741
|
+
// Re-sort descending so the lowest available id is popped next.
|
|
4742
|
+
this.fingers.sort((a, b) => b - a);
|
|
4720
4743
|
}
|
|
4721
|
-
// 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
|
|
4722
|
-
this.fingers.sort((a, b) => b - a);
|
|
4723
4744
|
this.fingerIds.delete(touch.identifier);
|
|
4724
4745
|
};
|
|
4725
4746
|
const emitTouchData = (type, touches) => {
|
|
4726
4747
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
4727
4748
|
for (let t = 0; t < touches.length; t++) {
|
|
4728
4749
|
let byte = 2;
|
|
4729
|
-
const numTouches = 1;
|
|
4750
|
+
const numTouches = 1;
|
|
4730
4751
|
const touch = touches[t];
|
|
4752
|
+
const finger = this.fingerIds.get(touch.identifier);
|
|
4753
|
+
// Skip unknown identifiers (e.g., stale touch on a fast retap) — sending
|
|
4754
|
+
// 0 here would alias finger '0' and corrupt UE's touch state.
|
|
4755
|
+
if (finger === undefined) {
|
|
4756
|
+
continue;
|
|
4757
|
+
}
|
|
4731
4758
|
const { x, y } = this.getTouchPositionWithOffset(touch);
|
|
4732
|
-
Logger.info(`F${
|
|
4733
|
-
const
|
|
4734
|
-
const data =
|
|
4759
|
+
Logger.info(`F${finger}=(${x}, ${y})`);
|
|
4760
|
+
const coord = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4761
|
+
const data = this.touchView;
|
|
4735
4762
|
data.setUint8(0, type);
|
|
4736
4763
|
data.setUint8(1, numTouches);
|
|
4737
|
-
data.setUint16(byte,
|
|
4764
|
+
data.setUint16(byte, coord.x, true);
|
|
4738
4765
|
byte += 2;
|
|
4739
|
-
data.setUint16(byte,
|
|
4766
|
+
data.setUint16(byte, coord.y, true);
|
|
4740
4767
|
byte += 2;
|
|
4741
|
-
|
|
4742
|
-
if (finger) {
|
|
4743
|
-
data.setUint8(byte, finger);
|
|
4744
|
-
}
|
|
4768
|
+
data.setUint8(byte, finger);
|
|
4745
4769
|
byte += 1;
|
|
4746
|
-
// force is
|
|
4747
|
-
// iOs bug: Forced to be always 0.5 on all devices as we do not use forced touch any way;/
|
|
4770
|
+
// iOS bug: force is locked to 0.5 since forced touch is unused.
|
|
4748
4771
|
data.setUint8(byte, this.maxByteValue * 0.5);
|
|
4749
4772
|
byte += 1;
|
|
4750
|
-
data.setUint8(byte,
|
|
4773
|
+
data.setUint8(byte, coord.inRange ? 1 : 0);
|
|
4751
4774
|
byte += 1;
|
|
4752
4775
|
this.sendInputData(data.buffer);
|
|
4753
4776
|
}
|
|
@@ -4757,7 +4780,6 @@ class InputService extends SubService {
|
|
|
4757
4780
|
.subscribe((e) => {
|
|
4758
4781
|
this.focusWindow();
|
|
4759
4782
|
const touches = e.changedTouches;
|
|
4760
|
-
// Assign a unique identifier to each touch.
|
|
4761
4783
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
4762
4784
|
for (let t = 0; t < touches.length; t++) {
|
|
4763
4785
|
rememberTouch(touches[t]);
|
|
@@ -4772,7 +4794,6 @@ class InputService extends SubService {
|
|
|
4772
4794
|
const touches = e.changedTouches;
|
|
4773
4795
|
Logger.info('touch end');
|
|
4774
4796
|
emitTouchData(MessageType.TouchEnd, touches);
|
|
4775
|
-
// Re-cycle unique identifiers previously assigned to each touch.
|
|
4776
4797
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
4777
4798
|
for (let t = 0; t < touches.length; t++) {
|
|
4778
4799
|
forgetTouch(touches[t]);
|
|
@@ -4790,45 +4811,41 @@ class InputService extends SubService {
|
|
|
4790
4811
|
window.focus();
|
|
4791
4812
|
}
|
|
4792
4813
|
emitMouseMove(x, y, deltaX, deltaY) {
|
|
4793
|
-
const
|
|
4794
|
-
this.lastNormalizedCoordinates = normalizeCoordinates;
|
|
4814
|
+
const coord = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4795
4815
|
const delta = this.normalizeAndQuantizeSigned(deltaX, deltaY);
|
|
4796
|
-
const data =
|
|
4816
|
+
const data = this.mouseMoveView;
|
|
4797
4817
|
data.setUint8(0, MessageType.MouseMove);
|
|
4798
|
-
data.setUint16(1,
|
|
4799
|
-
data.setUint16(3,
|
|
4818
|
+
data.setUint16(1, coord.x, true);
|
|
4819
|
+
data.setUint16(3, coord.y, true);
|
|
4800
4820
|
data.setInt16(5, delta.x, true);
|
|
4801
4821
|
data.setInt16(7, delta.y, true);
|
|
4802
4822
|
this.sendInputData(data.buffer);
|
|
4803
4823
|
}
|
|
4804
4824
|
emitMouseDown(button, x, y) {
|
|
4805
|
-
const
|
|
4806
|
-
|
|
4807
|
-
const data = new DataView(new ArrayBuffer(6));
|
|
4825
|
+
const coord = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4826
|
+
const data = this.mouseButtonView;
|
|
4808
4827
|
data.setUint8(0, MessageType.MouseDown);
|
|
4809
4828
|
data.setUint8(1, button);
|
|
4810
|
-
data.setUint16(2,
|
|
4811
|
-
data.setUint16(4,
|
|
4829
|
+
data.setUint16(2, coord.x, true);
|
|
4830
|
+
data.setUint16(4, coord.y, true);
|
|
4812
4831
|
this.sendInputData(data.buffer);
|
|
4813
4832
|
}
|
|
4814
4833
|
emitMouseUp(button, x, y) {
|
|
4815
|
-
const
|
|
4816
|
-
|
|
4817
|
-
const data = new DataView(new ArrayBuffer(6));
|
|
4834
|
+
const coord = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4835
|
+
const data = this.mouseButtonView;
|
|
4818
4836
|
data.setUint8(0, MessageType.MouseUp);
|
|
4819
4837
|
data.setUint8(1, button);
|
|
4820
|
-
data.setUint16(2,
|
|
4821
|
-
data.setUint16(4,
|
|
4838
|
+
data.setUint16(2, coord.x, true);
|
|
4839
|
+
data.setUint16(4, coord.y, true);
|
|
4822
4840
|
this.sendInputData(data.buffer);
|
|
4823
4841
|
}
|
|
4824
4842
|
emitMouseWheel(delta, x, y) {
|
|
4825
|
-
const
|
|
4826
|
-
|
|
4827
|
-
const data = new DataView(new ArrayBuffer(7));
|
|
4843
|
+
const coord = this.normalizeAndQuantizeUnsigned(x, y);
|
|
4844
|
+
const data = this.mouseWheelView;
|
|
4828
4845
|
data.setUint8(0, MessageType.MouseWheel);
|
|
4829
4846
|
data.setInt16(1, delta, true);
|
|
4830
|
-
data.setUint16(3,
|
|
4831
|
-
data.setUint16(5,
|
|
4847
|
+
data.setUint16(3, coord.x, true);
|
|
4848
|
+
data.setUint16(5, coord.y, true);
|
|
4832
4849
|
this.sendInputData(data.buffer);
|
|
4833
4850
|
}
|
|
4834
4851
|
releaseMouseButtons(buttons, x, y) {
|
|
@@ -4848,7 +4865,6 @@ class InputService extends SubService {
|
|
|
4848
4865
|
this.emitMouseUp(MouseButton.FifthButton, x, y);
|
|
4849
4866
|
}
|
|
4850
4867
|
}
|
|
4851
|
-
// If the user has any mouse buttons pressed, then press them again.
|
|
4852
4868
|
pressMouseButtons(buttons, x, y) {
|
|
4853
4869
|
if (buttons & MouseButtonsMask.PrimaryButton) {
|
|
4854
4870
|
this.emitMouseDown(MouseButton.MainButton, x, y);
|
|
@@ -4892,7 +4908,7 @@ class InputService extends SubService {
|
|
|
4892
4908
|
fromEvent(htmlVideoElement, 'wheel')
|
|
4893
4909
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4894
4910
|
.subscribe((e) => {
|
|
4895
|
-
this.emitMouseWheel(e.deltaY *
|
|
4911
|
+
this.emitMouseWheel(e.deltaY * WHEEL_DELTA_SCALE, e.offsetX, e.offsetY);
|
|
4896
4912
|
e.preventDefault();
|
|
4897
4913
|
});
|
|
4898
4914
|
}
|
|
@@ -4901,7 +4917,7 @@ class InputService extends SubService {
|
|
|
4901
4917
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4902
4918
|
.subscribe((e) => {
|
|
4903
4919
|
this.focusWindow();
|
|
4904
|
-
const data =
|
|
4920
|
+
const data = this.singleByteView;
|
|
4905
4921
|
data.setUint8(0, MessageType.MouseEnter);
|
|
4906
4922
|
this.sendInputData(data.buffer);
|
|
4907
4923
|
this.pressMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
@@ -4909,8 +4925,7 @@ class InputService extends SubService {
|
|
|
4909
4925
|
fromEvent(htmlVideoElement, 'mouseleave')
|
|
4910
4926
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4911
4927
|
.subscribe((e) => {
|
|
4912
|
-
|
|
4913
|
-
const data = new DataView(new ArrayBuffer(1));
|
|
4928
|
+
const data = this.singleByteView;
|
|
4914
4929
|
data.setUint8(0, MessageType.MouseLeave);
|
|
4915
4930
|
this.sendInputData(data.buffer);
|
|
4916
4931
|
this.releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
@@ -4918,8 +4933,8 @@ class InputService extends SubService {
|
|
|
4918
4933
|
}
|
|
4919
4934
|
// Browser keys do not have a charCode so we only need to test keyCode.
|
|
4920
4935
|
isKeyCodeBrowserKey(keyCode) {
|
|
4921
|
-
|
|
4922
|
-
|
|
4936
|
+
return ((keyCode >= FUNCTION_KEY_MIN && keyCode <= FUNCTION_KEY_MAX) ||
|
|
4937
|
+
keyCode === TAB_KEY_CODE);
|
|
4923
4938
|
}
|
|
4924
4939
|
getKeyCode(e) {
|
|
4925
4940
|
if (e.keyCode === SpecialKeyCodes.Shift && e.code === 'ShiftRight')
|
|
@@ -4932,9 +4947,7 @@ class InputService extends SubService {
|
|
|
4932
4947
|
return e.keyCode;
|
|
4933
4948
|
}
|
|
4934
4949
|
registerKeyboardEvents(availableKeys) {
|
|
4935
|
-
const availableKeyNames =
|
|
4936
|
-
return InvertedKeyMap[value];
|
|
4937
|
-
});
|
|
4950
|
+
const availableKeyNames = availableKeys.map((value) => InvertedKeyMap[value]);
|
|
4938
4951
|
const keyBlock = (event) => {
|
|
4939
4952
|
const code = event.code;
|
|
4940
4953
|
const isInputFieldFocused = event.target?.localName === 'input';
|
|
@@ -4949,7 +4962,6 @@ class InputService extends SubService {
|
|
|
4949
4962
|
}
|
|
4950
4963
|
startListenKeys(_filter) {
|
|
4951
4964
|
const filter = _filter ?? (() => false);
|
|
4952
|
-
// Use RxJS fromEvent with takeUntil to properly clean up subscriptions
|
|
4953
4965
|
fromEvent(document, 'keydown')
|
|
4954
4966
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
4955
4967
|
.subscribe((e) => {
|
|
@@ -4962,15 +4974,15 @@ class InputService extends SubService {
|
|
|
4962
4974
|
if (isCtrlOrCommand && isPlusOrMinus) {
|
|
4963
4975
|
return;
|
|
4964
4976
|
}
|
|
4965
|
-
this.
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
// Backspace
|
|
4971
|
-
// to
|
|
4977
|
+
const keyDown = this.keyDownBytes;
|
|
4978
|
+
keyDown[0] = MessageType.KeyDown;
|
|
4979
|
+
keyDown[1] = this.getKeyCode(e);
|
|
4980
|
+
keyDown[2] = Number(e.repeat);
|
|
4981
|
+
this.sendInputData(keyDown.buffer);
|
|
4982
|
+
// Backspace isn't a keypress in JS, but UE4 text-entry fields need it
|
|
4983
|
+
// to delete characters.
|
|
4972
4984
|
if (e.keyCode === SpecialKeyCodes.BackSpace) {
|
|
4973
|
-
const data =
|
|
4985
|
+
const data = this.keyPressView;
|
|
4974
4986
|
data.setUint8(0, MessageType.KeyPress);
|
|
4975
4987
|
data.setUint16(1, SpecialKeyCodes.BackSpace, true);
|
|
4976
4988
|
this.sendInputData(data.buffer);
|
|
@@ -4986,7 +4998,10 @@ class InputService extends SubService {
|
|
|
4986
4998
|
if (filter(e)) {
|
|
4987
4999
|
return;
|
|
4988
5000
|
}
|
|
4989
|
-
|
|
5001
|
+
const keyUp = this.keyUpBytes;
|
|
5002
|
+
keyUp[0] = MessageType.KeyUp;
|
|
5003
|
+
keyUp[1] = this.getKeyCode(e);
|
|
5004
|
+
this.sendInputData(keyUp.buffer);
|
|
4990
5005
|
if (this.options.suppressBrowserKeys &&
|
|
4991
5006
|
this.isKeyCodeBrowserKey(e.keyCode)) {
|
|
4992
5007
|
e.preventDefault();
|
|
@@ -4998,7 +5013,7 @@ class InputService extends SubService {
|
|
|
4998
5013
|
if (filter(e)) {
|
|
4999
5014
|
return;
|
|
5000
5015
|
}
|
|
5001
|
-
const data =
|
|
5016
|
+
const data = this.keyPressView;
|
|
5002
5017
|
data.setUint8(0, MessageType.KeyPress);
|
|
5003
5018
|
data.setUint16(1, e.charCode, true);
|
|
5004
5019
|
this.sendInputData(data.buffer);
|
|
@@ -7236,5 +7251,5 @@ function provideUnrealModule() {
|
|
|
7236
7251
|
* Generated bundle index. Do not edit.
|
|
7237
7252
|
*/
|
|
7238
7253
|
|
|
7239
|
-
export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CONSOLE_COMMAND_DISABLE_MESSAGES, CONSOLE_COMMAND_ENABLE_MESSAGES, CONSOLE_COMMAND_PIXEL_QUALITY, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DEFAULT_RECONNECT_DELAY_MS, DEFAULT_RECONNECT_ENABLED, DEFAULT_RECONNECT_MAX_ATTEMPTS, DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE, DEFAULT_RECONNECT_ON_ICE_FAILURE, DESTROY_DISCONNECT_REASONS, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LoadingProgressService, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, smoothTransition, startStream, trackMixpanelEvent, trackTelemetryData, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
7254
|
+
export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CONSOLE_COMMAND_DISABLE_MESSAGES, CONSOLE_COMMAND_ENABLE_MESSAGES, CONSOLE_COMMAND_PIXEL_QUALITY, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DEFAULT_RECONNECT_DELAY_MS, DEFAULT_RECONNECT_ENABLED, DEFAULT_RECONNECT_MAX_ATTEMPTS, DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE, DEFAULT_RECONNECT_ON_ICE_FAILURE, DESTROY_DISCONNECT_REASONS, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LoadingProgressService, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, smoothTransition, startStream, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
7240
7255
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|