Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Enable/disable user input devices #136

Merged
merged 16 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Frontend/Docs/Resources/Images/settings-panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions Frontend/Docs/Settings Panel.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ This page will be updated with new features and commands as they become availabl
| **Control scheme** | If the scheme is `locked mouse` the browser will use `pointerlock` to capture your mouse, whereas if the scheme is `hovering mouse` you will retain your OS/browser cursor. |
| **Color scheme** | Allows you to switch between light mode and dark mode. |

### Input
| **Setting** | **Description** |
| --- | --- |
| **Keyboard input** | If enabled, captures and sends keyboard events to the Unreal Engine application. |
| **Mouse input** | If enabled, captures and sends mouse events to the Unreal Engine application. |
| **Touch input** | If enabled, captures and sends touch events to the Unreal Engine application. |
| **Gamepad input** | If enabled, captures and sends gamepad events to the Unreal Engine application. |
| **XR controller input** | If enabled, captures and sends XR controller events to the Unreal Engine application. |

### Encoder
| **Setting** | **Description** |
| --- | --- |
Expand Down
4 changes: 2 additions & 2 deletions Frontend/library/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions Frontend/library/src/Config/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export class Flags {
static StartVideoMuted = 'StartVideoMuted' as const;
static SuppressBrowserKeys = 'SuppressBrowserKeys' as const;
static UseMic = 'UseMic' as const;
static KeyboardInput = 'KeyboardInput' as const;
static MouseInput = 'MouseInput' as const;
static TouchInput = 'TouchInput' as const;
static GamepadInput = 'GamepadInput' as const;
static XRControllerInput = 'XRControllerInput' as const;
}

export type FlagsKeys = Exclude<keyof typeof Flags, 'prototype'>;
Expand Down Expand Up @@ -398,6 +403,61 @@ export class Config {
)
);

this.flags.set(
Flags.KeyboardInput,
new SettingFlag(
Flags.KeyboardInput,
'Keyboard input',
'If enabled, send keyboard events to streamer',
true,
useUrlParams
)
);

this.flags.set(
Flags.MouseInput,
new SettingFlag(
Flags.MouseInput,
'Mouse input',
'If enabled, send mouse events to streamer',
true,
useUrlParams
)
);

this.flags.set(
Flags.TouchInput,
new SettingFlag(
Flags.TouchInput,
'Touch input',
'If enabled, send touch events to streamer',
true,
useUrlParams
)
);

this.flags.set(
Flags.GamepadInput,
new SettingFlag(
Flags.GamepadInput,
'Gamepad input',
'If enabled, send gamepad events to streamer',
true,
useUrlParams
)
);

this.flags.set(
Flags.XRControllerInput,
new SettingFlag(
Flags.XRControllerInput,
'XR controller input',
'If enabled, send XR controller events to streamer',
true,
useUrlParams
)
);

hmuurine marked this conversation as resolved.
Show resolved Hide resolved
/**
* Numeric parameters
*/
Expand Down
39 changes: 31 additions & 8 deletions Frontend/library/src/Inputs/FakeTouchController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StreamMessageController } from '../UeInstanceMessage/StreamMessageContr
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
Expand All @@ -18,6 +19,9 @@ export class FakeTouchController implements ITouchController {
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
Expand All @@ -31,9 +35,28 @@ export class FakeTouchController implements ITouchController {
this.toStreamerMessagesProvider = toStreamerMessagesProvider;
this.videoElementProvider = videoElementProvider;
this.coordinateConverter = coordinateConverter;
document.ontouchstart = (ev: TouchEvent) => this.onTouchStart(ev);
document.ontouchend = (ev: TouchEvent) => this.onTouchEnd(ev);
document.ontouchmove = (ev: TouchEvent) => this.onTouchMove(ev);
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();
}

/**
Expand Down Expand Up @@ -62,8 +85,8 @@ export class FakeTouchController implements ITouchController {

const videoElementParent =
this.videoElementProvider.getVideoParentElement() as HTMLDivElement;
const mouseEvent = new MouseEvent(touch.type, first_touch);
videoElementParent.onmouseenter(mouseEvent);
const mouseEvent = new MouseEvent('mouseenter', first_touch);
videoElementParent.dispatchEvent(mouseEvent);

const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(
this.fakeTouchFinger.x,
Expand Down Expand Up @@ -107,8 +130,8 @@ export class FakeTouchController implements ITouchController {
coord.y
]);

const mouseEvent = new MouseEvent(touchEvent.type, touch);
videoElementParent.onmouseleave(mouseEvent);
const mouseEvent = new MouseEvent('mouseleave', touch);
videoElementParent.dispatchEvent(mouseEvent);
this.fakeTouchFinger = null;
break;
}
Expand Down Expand Up @@ -140,7 +163,7 @@ export class FakeTouchController implements ITouchController {
x - this.fakeTouchFinger.x,
y - this.fakeTouchFinger.y
);
toStreamerHandlers.get('MoveMouse')([
toStreamerHandlers.get('MouseMove')([
hmuurine marked this conversation as resolved.
Show resolved Hide resolved
coord.x,
coord.y,
delta.x,
Expand Down
56 changes: 42 additions & 14 deletions Frontend/library/src/Inputs/GamepadController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { Logger } from '../Logger/Logger';
import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
import { EventListenerTracker } from '../Util/EventListenerTracker';
import { Controller } from './GamepadTypes';

/**
Expand All @@ -12,35 +13,60 @@ export class GamePadController {
requestAnimationFrame: (callback: FrameRequestCallback) => number;
toStreamerMessagesProvider: StreamMessageController;

// Utility for keeping track of event handlers and unregistering them
private gamePadEventListenerTracker = new EventListenerTracker();

/**
* @param toStreamerMessagesProvider - Stream message instance
*/
constructor(toStreamerMessagesProvider: StreamMessageController) {
this.toStreamerMessagesProvider = toStreamerMessagesProvider;

this.requestAnimationFrame =
this.requestAnimationFrame = (
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.requestAnimationFrame;
window.requestAnimationFrame
).bind(window);
const browserWindow = window as Window;
if ('GamepadEvent' in browserWindow) {
window.addEventListener('gamepadconnected', (ev: GamepadEvent) =>
this.gamePadConnectHandler(ev)
const onGamePadConnected = (ev: GamepadEvent) =>
this.gamePadConnectHandler(ev);
const onGamePadDisconnected = (ev: GamepadEvent) =>
this.gamePadDisconnectHandler(ev);
window.addEventListener('gamepadconnected', onGamePadConnected);
window.addEventListener('gamepaddisconnected', onGamePadDisconnected);
this.gamePadEventListenerTracker.addUnregisterCallback(
() => window.removeEventListener('gamepadconnected', onGamePadConnected)
);
window.addEventListener('gamepaddisconnected', (ev: GamepadEvent) =>
this.gamePadDisconnectHandler(ev)
this.gamePadEventListenerTracker.addUnregisterCallback(
() => window.removeEventListener('gamepaddisconnected', onGamePadDisconnected)
);
} else if ('WebKitGamepadEvent' in browserWindow) {
window.addEventListener(
'webkitgamepadconnected',
(ev: GamepadEvent) => this.gamePadConnectHandler(ev)
const onWebkitGamePadConnected = (ev: GamepadEvent) => this.gamePadConnectHandler(ev);
const onWebkitGamePadDisconnected = (ev: GamepadEvent) => this.gamePadDisconnectHandler(ev);
window.addEventListener('webkitgamepadconnected', onWebkitGamePadConnected);
window.addEventListener('webkitgamepaddisconnected', onWebkitGamePadDisconnected);
this.gamePadEventListenerTracker.addUnregisterCallback(
() => window.removeEventListener('webkitgamepadconnected', onWebkitGamePadConnected)
);
window.addEventListener(
'webkitgamepaddisconnected',
(ev: GamepadEvent) => this.gamePadDisconnectHandler(ev)
this.gamePadEventListenerTracker.addUnregisterCallback(
() => window.removeEventListener('webkitgamepaddisconnected', onWebkitGamePadDisconnected)
);
}
this.controllers = [];
for (const gamepad of navigator.getGamepads()) {
if (gamepad) {
this.gamePadConnectHandler(new GamepadEvent('gamepadconnected', { gamepad }));
}
}
}

/**
* Unregisters all event handlers
*/
unregisterGamePadEvents() {
this.gamePadEventListenerTracker.unregisterAll();
this.controllers = [];
}

/**
Expand All @@ -64,7 +90,7 @@ export class GamePadController {
'gamepad: ' + gamepad.id + ' connected',
6
);
window.requestAnimationFrame(() => this.updateStatus());
this.requestAnimationFrame(() => this.updateStatus());
}

/**
Expand Down Expand Up @@ -185,7 +211,9 @@ export class GamePadController {
}
this.controllers[controllerIndex].prevState = currentState;
}
this.requestAnimationFrame(() => this.updateStatus());
hmuurine marked this conversation as resolved.
Show resolved Hide resolved
if (this.controllers.length > 0) {
this.requestAnimationFrame(() => this.updateStatus());
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions Frontend/library/src/Inputs/HoveringMouseEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export class HoveringMouseEvents implements IMouseEvents {
this.mouseController = mouseController;
}

/**
* Unregister event handlers
*/
unregisterMouseEvents(): void {
// empty for HoveringMouseEvents implementation
}

/**
* Handle the mouse move event, sends the mouse data to the UE Instance
* @param mouseEvent - Mouse Event
Expand Down
5 changes: 5 additions & 0 deletions Frontend/library/src/Inputs/IMouseEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ export interface IMouseEvents {
* @param mouseEvent - mouse event
*/
handleContextMenu?(mouseEvent: MouseEvent): void;

/**
* Unregisters any registered mouse event handlers
*/
unregisterMouseEvents(): void;
}
5 changes: 5 additions & 0 deletions Frontend/library/src/Inputs/ITouchController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ export interface ITouchController {
* @param touchEvent - Touch Event Data
*/
onTouchMove(touchEvent: TouchEvent): void;

/**
* Unregisters all touch event handlers
*/
unregisterTouchEvents(): void;
}
Loading