mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-04 22:57:19 +02:00
Add microphone action for Game Bar
This commit is contained in:
parent
5c9202119b
commit
362c5386d1
@ -213,6 +213,7 @@ function main() {
|
||||
// Setup UI
|
||||
addCss();
|
||||
Toast.setup();
|
||||
getPref(PrefKey.GAME_BAR_ENABLED) && GameBar.getInstance();
|
||||
BX_FLAGS.PreloadUi && setupStreamUi();
|
||||
|
||||
StreamBadges.setupEvents();
|
||||
|
81
src/modules/game-bar/action-microphone.ts
Normal file
81
src/modules/game-bar/action-microphone.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { BxEvent, XcloudEvent } from "@utils/bx-event";
|
||||
import { BxIcon } from "@utils/bx-icon";
|
||||
import { createButton, ButtonStyle, CE } from "@utils/html";
|
||||
import { t } from "@utils/translation";
|
||||
import { BaseGameBarAction } from "./action-base";
|
||||
|
||||
enum MicrophoneState {
|
||||
REQUESTED = 'Requested',
|
||||
ENABLED = 'Enabled',
|
||||
MUTED = 'Muted',
|
||||
NOT_ALLOWED = 'NotAllowed',
|
||||
NOT_FOUND = 'NotFound',
|
||||
}
|
||||
|
||||
export class MicrophoneAction extends BaseGameBarAction {
|
||||
$content: HTMLElement;
|
||||
|
||||
visible: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const onClick = (e: Event) => {
|
||||
BxEvent.dispatch(window, BxEvent.GAME_BAR_ACTION_ACTIVATED);
|
||||
const state = this.$content.getAttribute('data-enabled');
|
||||
const enableMic = state === 'true' ? false : true;
|
||||
|
||||
try {
|
||||
window.BX_EXPOSED.streamSession.tryEnableChatAsync(enableMic);
|
||||
this.$content.setAttribute('data-enabled', enableMic.toString());
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const $btnDefault = createButton({
|
||||
style: ButtonStyle.GHOST,
|
||||
icon: BxIcon.MICROPHONE,
|
||||
title: t('show-touch-controller'),
|
||||
onClick: onClick,
|
||||
classes: ['bx-activated'],
|
||||
});
|
||||
|
||||
const $btnMuted = createButton({
|
||||
style: ButtonStyle.GHOST,
|
||||
icon: BxIcon.MICROPHONE_MUTED,
|
||||
title: t('hide-touch-controller'),
|
||||
onClick: onClick,
|
||||
});
|
||||
|
||||
this.$content = CE('div', {},
|
||||
$btnDefault,
|
||||
$btnMuted,
|
||||
);
|
||||
|
||||
this.reset();
|
||||
|
||||
window.addEventListener(BxEvent.STREAM_EVENT_TARGET_READY, e => {
|
||||
const eventTarget = window.BX_EXPOSED.eventTarget as EventTarget;
|
||||
eventTarget.addEventListener(XcloudEvent.MICROPHONE_STATE_CHANGED, e => {
|
||||
const state = window.BX_EXPOSED.streamSession.microphoneState as MicrophoneState;
|
||||
const enabled = state === MicrophoneState.ENABLED;
|
||||
|
||||
this.$content.setAttribute('data-enabled', enabled.toString());
|
||||
|
||||
// Show the button in Game Bar if the mic is enabled
|
||||
this.$content.classList.remove('bx-gone');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render(): HTMLElement {
|
||||
return this.$content;
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.visible = false;
|
||||
this.$content.classList.add('bx-gone');
|
||||
this.$content.setAttribute('data-enabled', 'false');
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import { BxIcon } from "@utils/bx-icon";
|
||||
import type { BaseGameBarAction } from "./action-base";
|
||||
import { STATES } from "@utils/global";
|
||||
import { PrefKey, getPref } from "@utils/preferences";
|
||||
import { MicrophoneAction } from "./action-microphone";
|
||||
|
||||
|
||||
export class GameBar {
|
||||
@ -38,6 +39,7 @@ export class GameBar {
|
||||
this.actions = [
|
||||
new ScreenshotAction(),
|
||||
...(STATES.hasTouchSupport && (getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== 'off') ? [new TouchControlAction()] : []),
|
||||
new MicrophoneAction(),
|
||||
];
|
||||
|
||||
// Render actions
|
||||
|
@ -4,6 +4,7 @@ import { getPref, PrefKey } from "@utils/preferences";
|
||||
import { VibrationManager } from "@modules/vibration-manager";
|
||||
import { BxLogger } from "@utils/bx-logger";
|
||||
import { hashCode } from "@utils/utils";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
|
||||
type PatchArray = (keyof typeof PATCHES)[];
|
||||
|
||||
@ -496,6 +497,45 @@ BxLogger.info('patchRemotePlayMkb', ${configsVar});
|
||||
str = str.replace(text, newCode);
|
||||
return str;
|
||||
},
|
||||
|
||||
exposeEventTarget(str: string) {
|
||||
const text ='this._eventTarget=new EventTarget';
|
||||
if (!str.includes(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const newCode = `
|
||||
window.BX_EXPOSED.eventTarget = ${text},
|
||||
window.dispatchEvent(new Event('${BxEvent.STREAM_EVENT_TARGET_READY}'))
|
||||
`;
|
||||
|
||||
str = str.replace(text, newCode);
|
||||
return str;
|
||||
},
|
||||
|
||||
exposeStreamSession(str: string) {
|
||||
const text =',this._connectionType=';
|
||||
if (!str.includes(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const newCode = `;
|
||||
|
||||
window.BX_EXPOSED.streamSession = this;
|
||||
|
||||
const orgSetMicrophoneState = this.setMicrophoneState.bind(this);
|
||||
this.setMicrophoneState = (e) => {
|
||||
console.log(e);
|
||||
orgSetMicrophoneState(e);
|
||||
};
|
||||
|
||||
window.dispatchEvent(new Event('${BxEvent.STREAM_SESSION_READY}'))
|
||||
|
||||
true` + text;
|
||||
|
||||
str = str.replace(text, newCode);
|
||||
return str;
|
||||
},
|
||||
};
|
||||
|
||||
let PATCH_ORDERS: PatchArray = [
|
||||
@ -503,6 +543,8 @@ let PATCH_ORDERS: PatchArray = [
|
||||
'overrideSettings',
|
||||
'broadcastPollingMode',
|
||||
|
||||
'exposeStreamSession',
|
||||
|
||||
getPref(PrefKey.UI_LAYOUT) !== 'default' && 'websiteLayout',
|
||||
getPref(PrefKey.LOCAL_CO_OP_ENABLED) && 'supportLocalCoOp',
|
||||
getPref(PrefKey.GAME_FORTNITE_FORCE_CONSOLE) && 'forceFortniteConsole',
|
||||
@ -538,6 +580,8 @@ let PLAYING_PATCH_ORDERS: PatchArray = [
|
||||
'patchStreamHud',
|
||||
'playVibration',
|
||||
|
||||
'exposeEventTarget',
|
||||
|
||||
// Patch volume control for normal stream
|
||||
getPref(PrefKey.AUDIO_ENABLE_VOLUME_CONTROL) && !getPref(PrefKey.STREAM_COMBINE_SOURCES) && 'patchAudioMediaStream',
|
||||
// Patch volume control for combined audio+video stream
|
||||
|
@ -120,8 +120,13 @@ export function injectStreamMenuButtons() {
|
||||
|
||||
let $elm: HTMLElement | null = $node as HTMLElement;
|
||||
|
||||
// Ignore SVG elements
|
||||
if ($elm instanceof SVGSVGElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Error Page: .PureErrorPage.ErrorScreen
|
||||
if ($elm.className.includes('PureErrorPage')) {
|
||||
if ($elm.className?.includes('PureErrorPage')) {
|
||||
BxEvent.dispatch(window, BxEvent.STREAM_ERROR_PAGE);
|
||||
return;
|
||||
}
|
||||
@ -133,7 +138,7 @@ export function injectStreamMenuButtons() {
|
||||
}
|
||||
|
||||
// Render badges
|
||||
if ($elm.className.startsWith('StreamMenu-module__container')) {
|
||||
if ($elm.className?.startsWith('StreamMenu-module__container')) {
|
||||
BxEvent.dispatch(window, BxEvent.STREAM_MENU_SHOWN);
|
||||
|
||||
const $btnCloseHud = document.querySelector('button[class*=StreamMenu-module__backButton]');
|
||||
@ -175,7 +180,7 @@ export function injectStreamMenuButtons() {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($elm.className.startsWith('Overlay-module_') || $elm.className.startsWith('InProgressScreen')) {
|
||||
if ($elm.className?.startsWith('Overlay-module_') || $elm.className?.startsWith('InProgressScreen')) {
|
||||
$elm = $elm.querySelector('#StreamHud');
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import { StreamStats } from "@modules/stream/stream-stats";
|
||||
import { TouchController } from "@modules/touch-controller";
|
||||
import { t } from "@utils/translation";
|
||||
import { VibrationManager } from "@modules/vibration-manager";
|
||||
import { GameBar } from "../game-bar/game-bar";
|
||||
import { Screenshot } from "@/utils/screenshot";
|
||||
|
||||
|
||||
@ -477,7 +476,6 @@ export function setupStreamUi() {
|
||||
StreamStats.render();
|
||||
|
||||
Screenshot.setup();
|
||||
getPref(PrefKey.GAME_BAR_ENABLED) && GameBar.getInstance();
|
||||
}
|
||||
|
||||
updateVideoPlayerCss();
|
||||
|
@ -19,6 +19,9 @@ export enum BxEvent {
|
||||
STREAM_WEBRTC_CONNECTED = 'bx-stream-webrtc-connected',
|
||||
STREAM_WEBRTC_DISCONNECTED = 'bx-stream-webrtc-disconnected',
|
||||
|
||||
STREAM_EVENT_TARGET_READY = 'bx-stream-event-target-ready',
|
||||
STREAM_SESSION_READY = 'bx-stream-session-ready',
|
||||
|
||||
CUSTOM_TOUCH_LAYOUTS_LOADED = 'bx-custom-touch-layouts-loaded',
|
||||
|
||||
REMOTE_PLAY_READY = 'bx-remote-play-ready',
|
||||
@ -31,6 +34,10 @@ export enum BxEvent {
|
||||
GAME_BAR_ACTION_ACTIVATED = 'bx-game-bar-action-activated',
|
||||
}
|
||||
|
||||
export enum XcloudEvent {
|
||||
MICROPHONE_STATE_CHANGED = 'microphoneStateChanged',
|
||||
}
|
||||
|
||||
export namespace BxEvent {
|
||||
export function dispatch(target: HTMLElement | Window, eventName: string, data?: any) {
|
||||
if (!eventName) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user