UNPKG

@epicgames-ps/lib-pixelstreamingfrontend-ue5.4

Version:
200 lines (183 loc) 7.63 kB
// Copyright Epic Games, Inc. All Rights Reserved. import { CoordinateConverter } from '../Util/CoordinateConverter'; import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController'; import { VideoPlayer } from '../VideoPlayer/VideoPlayer'; import { ITouchController } from './ITouchController'; import { MouseButton } from './MouseButtons'; import { EventListenerTracker } from '../Util/EventListenerTracker'; /** * Allows for the usage of fake touch events and implements ITouchController * @param dataChannelController - The controller for the Data channel * @param videoElementParent - The video player DOM element */ export class FakeTouchController implements ITouchController { fakeTouchFinger: FakeTouchFinger; toStreamerMessagesProvider: StreamMessageController; videoElementProvider: VideoPlayer; coordinateConverter: CoordinateConverter; videoElementParentClientRect: DOMRect; // Utility for keeping track of event handlers and unregistering them private touchEventListenerTracker = new EventListenerTracker(); /** * @param toStreamerMessagesProvider - Stream message instance * @param videoElementProvider - Video element instance * @param coordinateConverter - A coordinate converter instance */ constructor( toStreamerMessagesProvider: StreamMessageController, videoElementProvider: VideoPlayer, coordinateConverter: CoordinateConverter ) { this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.videoElementProvider = videoElementProvider; this.coordinateConverter = coordinateConverter; const ontouchstart = (ev: TouchEvent) => this.onTouchStart(ev); const ontouchend = (ev: TouchEvent) => this.onTouchEnd(ev); const ontouchmove = (ev: TouchEvent) => this.onTouchMove(ev); document.addEventListener('touchstart', ontouchstart, { passive: false }); document.addEventListener('touchend', ontouchend, { passive: false }); document.addEventListener('touchmove', ontouchmove, { passive: false }); this.touchEventListenerTracker.addUnregisterCallback( () => document.removeEventListener('touchstart', ontouchstart) ); this.touchEventListenerTracker.addUnregisterCallback( () => document.removeEventListener('touchend', ontouchend) ); this.touchEventListenerTracker.addUnregisterCallback( () => document.removeEventListener('touchmove', ontouchmove) ); } /** * Unregister all touch events */ unregisterTouchEvents() { this.touchEventListenerTracker.unregisterAll(); } /** * Sets the video Element Parent Client Rect numbers for this class * @param videoElementParentClientRect - a html ElementParentClientRect object */ setVideoElementParentClientRect(videoElementParentClientRect: DOMRect) { this.videoElementParentClientRect = videoElementParentClientRect; } /** * When a touch event begins * @param touch - the activating touch event */ onTouchStart(touch: TouchEvent): void { if (!this.videoElementProvider.isVideoReady() || touch.target !== this.videoElementProvider.getVideoElement()) { return; } if (this.fakeTouchFinger == null) { const first_touch = touch.changedTouches[0]; this.fakeTouchFinger = new FakeTouchFinger( first_touch.identifier, first_touch.clientX - this.videoElementParentClientRect.left, first_touch.clientY - this.videoElementParentClientRect.top ); const videoElementParent = this.videoElementProvider.getVideoParentElement() as HTMLDivElement; const mouseEvent = new MouseEvent('mouseenter', first_touch); videoElementParent.dispatchEvent(mouseEvent); const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned( this.fakeTouchFinger.x, this.fakeTouchFinger.y ); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDown')([ MouseButton.mainButton, coord.x, coord.y ]); } touch.preventDefault(); } /** * When a touch event ends * @param touchEvent - the activating touch event */ onTouchEnd(touchEvent: TouchEvent): void { if (!this.videoElementProvider.isVideoReady() || this.fakeTouchFinger == null) { return; } const videoElementParent = this.videoElementProvider.getVideoParentElement(); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; for (let t = 0; t < touchEvent.changedTouches.length; t++) { const touch = touchEvent.changedTouches[t]; if (touch.identifier === this.fakeTouchFinger.id) { const x = touch.clientX - this.videoElementParentClientRect.left; const y = touch.clientY - this.videoElementParentClientRect.top; const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(x, y); toStreamerHandlers.get('MouseUp')([ MouseButton.mainButton, coord.x, coord.y ]); const mouseEvent = new MouseEvent('mouseleave', touch); videoElementParent.dispatchEvent(mouseEvent); this.fakeTouchFinger = null; break; } } touchEvent.preventDefault(); } /** * On a Move touch event * @param touchEvent - the activating touch event */ onTouchMove(touchEvent: TouchEvent): void { if (!this.videoElementProvider.isVideoReady() || this.fakeTouchFinger == null) { return; } const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; for (let t = 0; t < touchEvent.touches.length; t++) { const touch = touchEvent.touches[t]; if (touch.identifier === this.fakeTouchFinger.id) { const x = touch.clientX - this.videoElementParentClientRect.left; const y = touch.clientY - this.videoElementParentClientRect.top; const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(x, y); const delta = this.coordinateConverter.normalizeAndQuantizeSigned( x - this.fakeTouchFinger.x, y - this.fakeTouchFinger.y ); toStreamerHandlers.get('MouseMove')([ coord.x, coord.y, delta.x, delta.y ]); this.fakeTouchFinger.x = x; this.fakeTouchFinger.y = y; break; } } touchEvent.preventDefault(); } } /** * The interface for finger position mapping */ export class FakeTouchFinger { id: number; x: number; y: number; /** * @param id - the button id * @param x - the x axis value * @param y - the y axis value */ constructor(id: number, x: number, y: number) { this.id = id; this.x = x; this.y = y; } }