Compare commits

...

13 Commits

2 changed files with 153 additions and 62 deletions

View File

@ -1,5 +1,5 @@
// ==UserScript== // ==UserScript==
// @name Better xCloud // @name Better xCloud
// @namespace https://github.com/redphx // @namespace https://github.com/redphx
// @version 3.5.1 // @version 3.5.2
// ==/UserScript== // ==/UserScript==

View File

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name Better xCloud // @name Better xCloud
// @namespace https://github.com/redphx // @namespace https://github.com/redphx
// @version 3.5.1 // @version 3.5.2
// @description Improve Xbox Cloud Gaming (xCloud) experience // @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx // @author redphx
// @license MIT // @license MIT
@ -16,7 +16,7 @@
/* ADDITIONAL CODE */ /* ADDITIONAL CODE */
const SCRIPT_VERSION = '3.5.1'; const SCRIPT_VERSION = '3.5.2';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud'; const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
// Setup flags // Setup flags
@ -491,7 +491,7 @@ const Translations = {
"左下", "左下",
"좌측 하단", "좌측 하단",
"Lewy dolny róg", "Lewy dolny róg",
"Inferior Esquerdo", "Inferior esquerdo",
"Левый нижний угол", "Левый нижний угол",
"Sol alt", "Sol alt",
"Внизу ліворуч", "Внизу ліворуч",
@ -508,7 +508,7 @@ const Translations = {
"右下", "右下",
"우측 하단", "우측 하단",
"Prawy dolny róg", "Prawy dolny róg",
"Inferior-direito", "Inferior direito",
"Правый нижний угол", "Правый нижний угол",
"Sağ alt", "Sağ alt",
"Внизу праворуч", "Внизу праворуч",
@ -669,7 +669,7 @@ const Translations = {
"关闭", "关闭",
], ],
"combine-audio-video-streams": [ "combine-audio-video-streams": [
, "Audio- und Video-Streams kombinieren",
"Gabung audio & video stream", "Gabung audio & video stream",
"Combine audio & video streams", "Combine audio & video streams",
, ,
@ -686,7 +686,7 @@ const Translations = {
"合并视频音频流", "合并视频音频流",
], ],
"combine-audio-video-streams-summary": [ "combine-audio-video-streams-summary": [
, "Könnte das Problem mit verzögertem Ton beheben",
"Mungkin memperbaiki masalah lag pada audio", "Mungkin memperbaiki masalah lag pada audio",
"May fix the laggy audio problem", "May fix the laggy audio problem",
, ,
@ -695,7 +695,7 @@ const Translations = {
"音声の遅延を改善できる可能性があります", "音声の遅延を改善できる可能性があります",
, ,
"Może rozwiązać problem z zacinającym dźwiękiem", "Może rozwiązać problem z zacinającym dźwiękiem",
"Pode corrigir o problema de áudio Laggy", "Pode corrigir o problema de áudio atrasado",
"Может исправить проблему подвисания звука", "Может исправить проблему подвисания звука",
"Sesteki gecikme sorununa çözüm olabilir", "Sesteki gecikme sorununa çözüm olabilir",
"Може виправити проблему із затримкою звуку", "Може виправити проблему із затримкою звуку",
@ -882,7 +882,7 @@ const Translations = {
"カスタム", "カスタム",
"사용자 지정", "사용자 지정",
"Niestandardowe", "Niestandardowe",
"Customizado", "Personalizado",
"Вручную", "Вручную",
"Özel", "Özel",
"Користувацькі", "Користувацькі",
@ -899,7 +899,7 @@ const Translations = {
"デッドゾーンのカウンターウエイト", "デッドゾーンのカウンターウエイト",
, ,
"Przeciwwaga martwej strefy", "Przeciwwaga martwej strefy",
"Contador da Zona Morta", "Contrapeso de zona morta",
"Противодействие мертвой зоне игры", "Противодействие мертвой зоне игры",
"Ölü alan denge ağırlığı", "Ölü alan denge ağırlığı",
"Противага Deadzone", "Противага Deadzone",
@ -1264,7 +1264,7 @@ const Translations = {
"启用", "启用",
], ],
"experimental": [ "experimental": [
, "Experimentell",
"Eksperimental", "Eksperimental",
"Experimental", "Experimental",
, ,
@ -1409,7 +1409,7 @@ const Translations = {
"Webページのスクロールバーを隠す", "Webページのスクロールバーを隠す",
, ,
"Ukryj pasek przewijania strony", "Ukryj pasek przewijania strony",
"Oculta a barra de rolagem da página", "Ocultar a barra de rolagem da página",
"Скрыть полосу прокрутки страницы", "Скрыть полосу прокрутки страницы",
"Yandaki kaydırma çubuğunu gizle", "Yandaki kaydırma çubuğunu gizle",
"Приховати смугу прокрутки вебсторінок", "Приховати смугу прокрутки вебсторінок",
@ -1579,7 +1579,7 @@ const Translations = {
"ロード画面", "ロード画面",
"로딩 화면", "로딩 화면",
"Ekran wczytywania", "Ekran wczytywania",
"Tela de Carregamento", "Tela de carregamento",
"Экран загрузки", "Экран загрузки",
"Yükleme ekranı", "Yükleme ekranı",
"Екран завантаження", "Екран завантаження",
@ -1698,7 +1698,7 @@ const Translations = {
"ゲーム内の設定で感度とデッドゾーンの調整が必要な場合があります", "ゲーム内の設定で感度とデッドゾーンの調整が必要な場合があります",
, ,
"Może być również konieczne dostosowanie czułości w grze i ustawienia 'martwej strefy' urządzenia", "Może być również konieczne dostosowanie czułości w grze i ustawienia 'martwej strefy' urządzenia",
"Você também pode precisar ajustar as configurações de sensibilidade e zona morta no jogo", "Você talvez também precise ajustar as configurações de sensibilidade e zona morta no jogo",
"Также может потребоваться изменить настройки чувствительности и мертвой зоны в игре", "Также может потребоваться изменить настройки чувствительности и мертвой зоны в игре",
"Bu seçenek etkinken bile oyun içi seçeneklerden hassasiyet ve ölü bölge ayarlarını düzeltmeniz gerekebilir", "Bu seçenek etkinken bile oyun içi seçeneklerden hassasiyet ve ölü bölge ayarlarını düzeltmeniz gerekebilir",
"Можливо, вам також доведеться регулювати чутливість і deadzone у параметрах гри", "Можливо, вам також доведеться регулювати чутливість і deadzone у параметрах гри",
@ -2004,7 +2004,7 @@ const Translations = {
"IPv6 サーバーを優先", "IPv6 サーバーを優先",
"IPv6 서버 우선", "IPv6 서버 우선",
"Preferuj serwer IPv6", "Preferuj serwer IPv6",
"Preferir servidor IPV6", "Preferir servidor IPv6",
"Предпочитать IPv6 сервер", "Предпочитать IPv6 сервер",
"IPv6 sunucusunu tercih et", "IPv6 sunucusunu tercih et",
"Віддавати перевагу IPv6", "Віддавати перевагу IPv6",
@ -2174,7 +2174,7 @@ const Translations = {
"リモートプレイ", "リモートプレイ",
"리모트 플레이", "리모트 플레이",
"Gra zdalna", "Gra zdalna",
"Jogo Remoto", "Reprodução remota",
"Удаленная игра", "Удаленная игра",
"Uzaktan Bağlanma", "Uzaktan Bağlanma",
"Віддалена гра", "Віддалена гра",
@ -2361,7 +2361,7 @@ const Translations = {
"スクリーンショットにビデオフィルターを適用", "スクリーンショットにビデオフィルターを適用",
, ,
"Stosuje filtry wideo do zrzutów ekranu", "Stosuje filtry wideo do zrzutów ekranu",
"Aplicar filtros às capturas de tela", "Aplicar filtros de vídeo às capturas de tela",
"Применяет фильтры видео к скриншотам", "Применяет фильтры видео к скриншотам",
"Görsel filtreleri ekran görüntülerine de uygular", "Görsel filtreleri ekran görüntülerine de uygular",
"Застосовує відеофільтри до знімків екрана", "Застосовує відеофільтри до знімків екрана",
@ -2786,7 +2786,7 @@ const Translations = {
"スティックの減衰の最小値", "スティックの減衰の最小値",
, ,
"Minimalne opóźnienie drążka", "Minimalne opóźnienie drążka",
"Mínimo decaimento do analógico", "Tempo mínimo de redefinição do analógico",
"Минимальная перезарядка стика", "Минимальная перезарядка стика",
"Çubuğun ortalanma süresi minimumu", "Çubuğun ortalanma süresi minimumu",
"Мінімальне згасання стіка", "Мінімальне згасання стіка",
@ -2803,7 +2803,7 @@ const Translations = {
"スティックの減衰の強さ", "スティックの減衰の強さ",
, ,
"Siła opóźnienia drążka", "Siła opóźnienia drążka",
"Força de decaimento do analógico", "Velocidade de redefinição do analógico",
"Скорость перезарядки стика", "Скорость перезарядки стика",
"Çubuğun ortalanma gücü", "Çubuğun ortalanma gücü",
"Сила згасання стіка", "Сила згасання стіка",
@ -2854,7 +2854,7 @@ const Translations = {
"Better xCloudをサポート", "Better xCloudをサポート",
, ,
"Wesprzyj Better xCloud", "Wesprzyj Better xCloud",
"Suporte ao Better xCloud", "Apoie o Better xCloud",
"Поддержать Better xCloud", "Поддержать Better xCloud",
"Better xCloud'a destek ver", "Better xCloud'a destek ver",
"Підтримати Better xCloud", "Підтримати Better xCloud",
@ -2990,7 +2990,7 @@ const Translations = {
"ミュートカラー", "ミュートカラー",
"저채도 색상", "저채도 색상",
"Stonowane kolory", "Stonowane kolory",
"Cores silenciadas", "Cores opacas",
"Приглушенные цвета", "Приглушенные цвета",
"Yumuşak renkler", "Yumuşak renkler",
"Приглушені кольори", "Приглушені кольори",
@ -3041,7 +3041,7 @@ const Translations = {
"上", "上",
"중앙 상단", "중앙 상단",
"Wyśrodkowany na górze", "Wyśrodkowany na górze",
"Superior-centralizado", "Superior centralizado",
"Сверху", "Сверху",
"Orta üst", "Orta üst",
"Зверху по центру", "Зверху по центру",
@ -3058,7 +3058,7 @@ const Translations = {
"左上", "左上",
"좌측 상단", "좌측 상단",
"Lewy górny róg", "Lewy górny róg",
"Superior-esquerdo", "Superior esquerdo",
"Левый верхний угол", "Левый верхний угол",
"Sol üst", "Sol üst",
"Зверху ліворуч", "Зверху ліворуч",
@ -3075,7 +3075,7 @@ const Translations = {
"右上", "右上",
"우측 상단", "우측 상단",
"Prawy górny róg", "Prawy górny róg",
"Superior-direito", "Superior direito",
"Справа", "Справа",
"Sağ üst", "Sağ üst",
"Зверху праворуч", "Зверху праворуч",
@ -3673,40 +3673,56 @@ class RemotePlay {
if (!RemotePlay.#CONSOLES || RemotePlay.#CONSOLES.length === 0) { if (!RemotePlay.#CONSOLES || RemotePlay.#CONSOLES.length === 0) {
$fragment.appendChild(CE('span', {}, t('no-consoles-found'))); $fragment.appendChild(CE('span', {}, t('no-consoles-found')));
} else { RemotePlay.#$content = CE('div', {}, $fragment);
return;
}
const $settingNote = CE('p', {}); const $settingNote = CE('p', {});
const resolutions = [1080, 720]; const resolutions = [1080, 720];
const currentResolution = getPref(Preferences.REMOTE_PLAY_RESOLUTION); const currentResolution = getPref(Preferences.REMOTE_PLAY_RESOLUTION);
const $resolutionSelect = CE('select', {}); const $resolutionGroup = CE('div', {});
for (const resolution of resolutions) { for (const resolution of resolutions) {
const value = `${resolution}p`; const value = `${resolution}p`;
const id = `bx_radio_xhome_resolution_${resolution}`;
const $option = CE('option', {'value': value}, value); const $radio = CE('input', {
if (currentResolution === value) { 'type': 'radio',
$option.selected = true; 'value': value,
} 'id': id,
'name': 'bx_radio_xhome_resolution',
}, value);
$resolutionSelect.appendChild($option); $radio.addEventListener('change', e => {
} const value = e.target.value;
$resolutionSelect.addEventListener('change', e => {
const value = $resolutionSelect.value;
$settingNote.textContent = value === '1080p' ? '✅ ' + t('can-stream-xbox-360-games') : '❌ ' + t('cant-stream-xbox-360-games'); $settingNote.textContent = value === '1080p' ? '✅ ' + t('can-stream-xbox-360-games') : '❌ ' + t('cant-stream-xbox-360-games');
setPref(Preferences.REMOTE_PLAY_RESOLUTION, value); setPref(Preferences.REMOTE_PLAY_RESOLUTION, value);
}); });
$resolutionSelect.dispatchEvent(new Event('change'));
const $label = CE('label', {
'for': id,
'class': 'bx-remote-play-resolution',
}, $radio, `${resolution}p`);
$resolutionGroup.appendChild($label);
if (currentResolution === value) {
$radio.checked = true;
$radio.dispatchEvent(new Event('change'));
}
}
const $qualitySettings = CE('div', {'class': 'bx-remote-play-settings'}, const $qualitySettings = CE('div', {'class': 'bx-remote-play-settings'},
CE('div', {}, CE('div', {},
CE('label', {}, t('target-resolution'), $settingNote), CE('label', {}, t('target-resolution'), $settingNote),
$resolutionSelect, $resolutionGroup,
) )
); );
$fragment.appendChild($qualitySettings); $fragment.appendChild($qualitySettings);
}
// Render concoles list
for (let con of RemotePlay.#CONSOLES) { for (let con of RemotePlay.#CONSOLES) {
let $connectButton; let $connectButton;
const $child = CE('div', {'class': 'bx-remote-play-device-wrapper'}, const $child = CE('div', {'class': 'bx-remote-play-device-wrapper'},
@ -3732,6 +3748,14 @@ class RemotePlay {
$fragment.appendChild($child); $fragment.appendChild($child);
} }
// Add Help button
$fragment.appendChild(createButton({
icon: Icon.QUESTION,
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
url: 'https://better-xcloud.github.io/remote-play',
label: t('help'),
}));
RemotePlay.#$content = CE('div', {}, $fragment); RemotePlay.#$content = CE('div', {}, $fragment);
} }
@ -4986,7 +5010,7 @@ class MkbPreset {
[MkbPreset.KEY_MOUSE_STICK_DECAY_STRENGTH]: { [MkbPreset.KEY_MOUSE_STICK_DECAY_STRENGTH]: {
label: t('stick-decay-strength'), label: t('stick-decay-strength'),
type: SettingElement.TYPE_NUMBER_STEPPER, type: SettingElement.TYPE_NUMBER_STEPPER,
default: 18, default: 100,
min: 10, min: 10,
max: 100, max: 100,
@ -4999,7 +5023,7 @@ class MkbPreset {
[MkbPreset.KEY_MOUSE_STICK_DECAY_MIN]: { [MkbPreset.KEY_MOUSE_STICK_DECAY_MIN]: {
label: t('stick-decay-minimum'), label: t('stick-decay-minimum'),
type: SettingElement.TYPE_NUMBER_STEPPER, type: SettingElement.TYPE_NUMBER_STEPPER,
default: 6, default: 10,
min: 1, min: 1,
max: 10, max: 10,
@ -5266,8 +5290,10 @@ class MkbHandler {
static get DEFAULT_DEADZONE_COUNTERWEIGHT() { return 0.01; } static get DEFAULT_DEADZONE_COUNTERWEIGHT() { return 0.01; }
static get MAXIMUM_STICK_RANGE() { return 1.1; } static get MAXIMUM_STICK_RANGE() { return 1.1; }
VIRTUAL_GAMEPAD_ID = 'Xbox 360 Controller';
#VIRTUAL_GAMEPAD = { #VIRTUAL_GAMEPAD = {
id: 'Xbox 360 Controller', id: MkbHandler.VIRTUAL_GAMEPAD_ID,
index: 3, index: 3,
connected: false, connected: false,
hapticActuators: null, hapticActuators: null,
@ -5389,7 +5415,7 @@ class MkbHandler {
const isKeyDown = e.type === 'keydown'; const isKeyDown = e.type === 'keydown';
// Toggle MKB feature // Toggle MKB feature
if (isKeyDown && e.code === 'F9') { if (isKeyDown && e.code === 'F8') {
e.preventDefault(); e.preventDefault();
this.toggle(); this.toggle();
return; return;
@ -5529,7 +5555,7 @@ class MkbHandler {
this.#enabled = !this.#enabled; this.#enabled = !this.#enabled;
this.#enabled ? document.pointerLockElement && this.start() : this.stop(); this.#enabled ? document.pointerLockElement && this.start() : this.stop();
Toast.show(t('mouse-and-keyboard'), t(this.#enabled ? 'enabled' : 'disabled')); Toast.show(t('mouse-and-keyboard'), t(this.#enabled ? 'enabled' : 'disabled'), {instant: true});
if (this.#enabled) { if (this.#enabled) {
!document.pointerLockElement && this.#waitForPointerLock(true); !document.pointerLockElement && this.#waitForPointerLock(true);
@ -5600,6 +5626,7 @@ class MkbHandler {
this.#$message = CE('div', {'class': 'bx-mkb-pointer-lock-msg bx-gone'}, this.#$message = CE('div', {'class': 'bx-mkb-pointer-lock-msg bx-gone'},
createButton({ createButton({
icon: Icon.MOUSE_SETTINGS, icon: Icon.MOUSE_SETTINGS,
style: ButtonStyle.PRIMARY,
onClick: e => { onClick: e => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -5609,7 +5636,7 @@ class MkbHandler {
}), }),
CE('div', {}, CE('div', {},
CE('p', {}, t('mkb-click-to-activate')), CE('p', {}, t('mkb-click-to-activate')),
CE('p', {}, t('press-key-to-toggle-mkb')({key: 'F9'})), CE('p', {}, t('press-key-to-toggle-mkb')({key: 'F8'})),
), ),
); );
@ -7904,6 +7931,26 @@ class Patcher {
return funcStr.replace(text, '.disableTelemetry=function(){return!0}'); return funcStr.replace(text, '.disableTelemetry=function(){return!0}');
}, },
disableTelemetryProvider: function(funcStr) {
const text = 'this.enableLightweightTelemetry=!';
if (!funcStr.includes(text)) {
return false;
}
const newCode = [
'this.trackEvent',
'this.trackPageView',
'this.trackHttpCompleted',
'this.trackHttpFailed',
'this.trackError',
'this.trackErrorLike',
'this.onTrackEvent',
'()=>{}',
].join('=');
return funcStr.replace(text, newCode + ';' + text);
},
// Disable IndexDB logging // Disable IndexDB logging
disableIndexDbLogging(funcStr) { disableIndexDbLogging(funcStr) {
const text = 'async addLog(e,t=1e4){'; const text = 'async addLog(e,t=1e4){';
@ -8004,7 +8051,7 @@ class Patcher {
}, },
enableXcloudLogger: function(funcStr) { enableXcloudLogger: function(funcStr) {
const text = 'this.telemetryProvider=e}log(e,t,r){'; const text = 'this.telemetryProvider=e}log(e,t,i){';
if (!funcStr.includes(text)) { if (!funcStr.includes(text)) {
return false; return false;
} }
@ -8268,6 +8315,8 @@ if (gamepadFound) {
'disableTelemetry', 'disableTelemetry',
], ],
getPref(Preferences.BLOCK_TRACKING) && ['disableTelemetryProvider'],
['disableStreamGate'], ['disableStreamGate'],
getPref(Preferences.UI_LAYOUT) === 'tv' && ['tvLayout'], getPref(Preferences.UI_LAYOUT) === 'tv' && ['tvLayout'],
@ -8582,10 +8631,12 @@ div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module
left: -9999px; left: -9999px;
} }
/* Remove the "Cloud Gaming" text in header */ /* Remove the "Cloud Gaming" text in header when the screen is too small */
@media screen and (max-width: 600px) {
header a[href="/play"] { header a[href="/play"] {
display: none; display: none;
} }
}
a.bx-button { a.bx-button {
display: inline-block; display: inline-block;
@ -9706,6 +9757,11 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
} }
} }
.bx-remote-play-container > .bx-button {
display: table;
margin: 0 0 0 auto;
}
.bx-remote-play-settings { .bx-remote-play-settings {
margin-bottom: 12px; margin-bottom: 12px;
padding-bottom: 12px; padding-bottom: 12px;
@ -9735,6 +9791,19 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
text-align: center; text-align: center;
} }
.bx-remote-play-resolution {
display: block;
}
.bx-remote-play-resolution input[type="radio"] {
accent-color: var(--bx-primary-button-color);
margin-right: 6px;
}
.bx-remote-play-resolution input[type="radio"]:focus {
accent-color: var(--bx-primary-button-hover-color);
}
.bx-remote-play-device-wrapper { .bx-remote-play-device-wrapper {
display: flex; display: flex;
margin-bottom: 12px; margin-bottom: 12px;
@ -9931,13 +10000,23 @@ body::-webkit-scrollbar {
function getPreferredServerRegion(shortName = false) { function getPreferredServerRegion(shortName = false) {
let preferredRegion = getPref(Preferences.SERVER_REGION); let preferredRegion = getPref(Preferences.SERVER_REGION);
if (preferredRegion in SERVER_REGIONS) { if (preferredRegion in SERVER_REGIONS) {
return shortName ? SERVER_REGIONS[preferredRegion].shortName : preferredRegion; if (shortName && SERVER_REGIONS[preferredRegion].shortName) {
return SERVER_REGIONS[preferredRegion].shortName;
} else {
return preferredRegion;
}
} }
for (let regionName in SERVER_REGIONS) { for (let regionName in SERVER_REGIONS) {
const region = SERVER_REGIONS[regionName]; const region = SERVER_REGIONS[regionName];
if (region.isDefault) { if (!region.isDefault) {
return shortName ? region.shortName : regionName; continue;
}
if (shortName && region.shortName) {
return region.shortName;
} else {
return regionName;
} }
} }
@ -10390,7 +10469,7 @@ function interceptHttpRequests() {
if (PREF_UI_LOADING_SCREEN_WAIT_TIME && url.includes('xboxlive.com') && url.includes('/waittime/')) { if (PREF_UI_LOADING_SCREEN_WAIT_TIME && url.includes('xboxlive.com') && url.includes('/waittime/')) {
const response = await NATIVE_FETCH(...arg); const response = await NATIVE_FETCH(...arg);
const json = await response.clone.json(); const json = await response.clone().json();
if (json.estimatedAllocationTimeInSeconds > 0) { if (json.estimatedAllocationTimeInSeconds > 0) {
// Setup wait time overlay // Setup wait time overlay
LoadingScreen.setupWaitTime(json.estimatedTotalWaitTimeInSeconds); LoadingScreen.setupWaitTime(json.estimatedTotalWaitTimeInSeconds);
@ -10701,6 +10780,7 @@ function setupSettingsUi() {
}); });
selectedValue = PREF_PREFERRED_REGION; selectedValue = PREF_PREFERRED_REGION;
setting.options = {}; setting.options = {};
for (let regionName in SERVER_REGIONS) { for (let regionName in SERVER_REGIONS) {
const region = SERVER_REGIONS[regionName]; const region = SERVER_REGIONS[regionName];
@ -10710,6 +10790,10 @@ function setupSettingsUi() {
if (region.isDefault) { if (region.isDefault) {
label += ` (${t('default')})`; label += ` (${t('default')})`;
value = 'default'; value = 'default';
if (selectedValue === regionName) {
selectedValue = 'default';
}
} }
setting.options[value] = label; setting.options[value] = label;
@ -10719,9 +10803,11 @@ function setupSettingsUi() {
const label = setting.options[value]; const label = setting.options[value];
const $option = CE('option', {value: value}, label); const $option = CE('option', {value: value}, label);
$option.selected = value === selectedValue || label.includes(selectedValue);
$control.appendChild($option); $control.appendChild($option);
} }
// Select preferred region
$control.value = selectedValue;
} else { } else {
if (settingId === Preferences.BETTER_XCLOUD_LOCALE) { if (settingId === Preferences.BETTER_XCLOUD_LOCALE) {
$control = PREFS.toElement(settingId, e => { $control = PREFS.toElement(settingId, e => {
@ -12013,6 +12099,11 @@ MkbHandler.setupEvents();
// Show a toast when connecting/disconecting controller // Show a toast when connecting/disconecting controller
function showGamepadToast(gamepad) { function showGamepadToast(gamepad) {
// Don't show Toast for virtual controller
if (gamepad.id === MkbHandler.VIRTUAL_GAMEPAD_ID) {
return;
}
console.log(gamepad); console.log(gamepad);
let text = '🎮'; let text = '🎮';