better-xcloud/src/utils/bx-exposed.ts

108 lines
4.1 KiB
TypeScript

import { ControllerShortcut } from "@/modules/controller-shortcut";
import { BxEvent } from "@utils/bx-event";
import { STATES } from "@utils/global";
import { getPref, PrefKey } from "@utils/preferences";
import { UserAgent } from "@utils/user-agent";
import { BxLogger } from "./bx-logger";
export enum InputType {
CONTROLLER = 'Controller',
MKB = 'MKB',
CUSTOM_TOUCH_OVERLAY = 'CustomTouchOverlay',
GENERIC_TOUCH = 'GenericTouch',
NATIVE_TOUCH = 'NativeTouch',
BATIVE_SENSOR = 'NativeSensor',
}
export const BxExposed = {
getTitleInfo: () => STATES.currentStream.titleInfo,
modifyTitleInfo: (titleInfo: XcloudTitleInfo): XcloudTitleInfo => {
// Clone the object since the original is read-only
titleInfo = structuredClone(titleInfo);
let supportedInputTypes = titleInfo.details.supportedInputTypes;
// Remove native MKB support on mobile browsers or by user's choice
if (getPref(PrefKey.NATIVE_MKB_DISABLED) || UserAgent.isMobile()) {
supportedInputTypes = supportedInputTypes.filter(i => i !== InputType.MKB);
}
titleInfo.details.hasMkbSupport = supportedInputTypes.includes(InputType.MKB);
if (STATES.hasTouchSupport) {
let touchControllerAvailability = getPref(PrefKey.STREAM_TOUCH_CONTROLLER);
// Disable touch control when gamepad found
if (touchControllerAvailability !== 'off' && getPref(PrefKey.STREAM_TOUCH_CONTROLLER_AUTO_OFF)) {
const gamepads = window.navigator.getGamepads();
let gamepadFound = false;
for (let gamepad of gamepads) {
if (gamepad && gamepad.connected) {
gamepadFound = true;
break;
}
}
gamepadFound && (touchControllerAvailability = 'off');
}
if (touchControllerAvailability === 'off') {
// Disable touch on all games (not native touch)
supportedInputTypes = supportedInputTypes.filter(i => i !== InputType.CUSTOM_TOUCH_OVERLAY && i !== InputType.GENERIC_TOUCH);
// Empty TABs
titleInfo.details.supportedTabs = [];
}
// Pre-check supported input types
titleInfo.details.hasTouchSupport = supportedInputTypes.includes(InputType.NATIVE_TOUCH) ||
supportedInputTypes.includes(InputType.CUSTOM_TOUCH_OVERLAY) ||
supportedInputTypes.includes(InputType.GENERIC_TOUCH);
if (!titleInfo.details.hasTouchSupport && touchControllerAvailability === 'all') {
// Add generic touch support for non touch-supported games
titleInfo.details.hasFakeTouchSupport = true;
supportedInputTypes.push(InputType.GENERIC_TOUCH);
}
}
titleInfo.details.supportedInputTypes = supportedInputTypes;
// Save this info in STATES
STATES.currentStream.titleInfo = titleInfo;
BxEvent.dispatch(window, BxEvent.TITLE_INFO_READY);
return titleInfo;
},
setupGainNode: ($media: HTMLMediaElement, audioStream: MediaStream) => {
if ($media instanceof HTMLAudioElement) {
$media.muted = true;
$media.addEventListener('playing', e => {
$media.muted = true;
$media.pause();
});
} else {
$media.muted = true;
$media.addEventListener('playing', e => {
$media.muted = true;
});
}
try {
const audioCtx = STATES.currentStream.audioContext!;
const source = audioCtx.createMediaStreamSource(audioStream);
const gainNode = audioCtx.createGain(); // call monkey-patched createGain() in BxAudioContext
source.connect(gainNode).connect(audioCtx.destination);
} catch (e) {
BxLogger.error('setupGainNode', e);
STATES.currentStream.audioGainNode = null;
}
},
handleControllerShortcut: ControllerShortcut.handle,
resetControllerShortcut: ControllerShortcut.reset,
};