Compare commits

..

17 Commits

2 changed files with 211 additions and 133 deletions

View File

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

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @name Better xCloud
// @namespace https://github.com/redphx
// @version 3.0.2.1
// @version 3.0.3
// @description Improve Xbox Cloud Gaming (xCloud) experience
// @author redphx
// @license MIT
@ -13,7 +13,7 @@
// ==/UserScript==
'use strict';
const SCRIPT_VERSION = '3.0.2.1';
const SCRIPT_VERSION = '3.0.3';
const SCRIPT_HOME = 'https://github.com/redphx/better-xcloud';
const ENABLE_XCLOUD_LOGGER = false;
@ -110,13 +110,27 @@ const createSvgIcon = (icon, strokeWidth=2) => {
return $svg;
};
const ButtonStyle = {};
ButtonStyle[ButtonStyle.PRIMARY = 1] = 'bx-primary';
ButtonStyle[ButtonStyle.DANGER = 2] = 'bx-danger';
ButtonStyle[ButtonStyle.GHOST = 4] = 'bx-ghost';
ButtonStyle[ButtonStyle.FOCUSABLE = 8] = 'bx-focusable';
ButtonStyle[ButtonStyle.FULL_WIDTH = 16] = 'bx-full-width';
ButtonStyle[ButtonStyle.FULL_HEIGHT = 32] = 'bx-full-height';
const ButtonStyleIndices = Object.keys(ButtonStyle).splice(0, Object.keys(ButtonStyle).length / 2).map(i => parseInt(i));
const createButton = options => {
const $btn = CE(options.url ? 'a' : 'button', {'class': 'bx-button'});
options.isPrimary && $btn.classList.add('bx-primary');
options.isDanger && $btn.classList.add('bx-danger');
options.isGhost && $btn.classList.add('bx-ghost');
const style = options.style || 0;
style && ButtonStyleIndices.forEach(index => {
(style & index) && $btn.classList.add(ButtonStyle[index]);
});
options.classes && $btn.classList.add(...options.classes);
options.icon && $btn.appendChild(createSvgIcon(options.icon, 4));
options.label && $btn.appendChild(CE('span', {}, options.label));
options.title && $btn.setAttribute('title', options.title);
@ -181,6 +195,7 @@ const Translations = {
"tr-TR": "Etkinleştir",
"uk-UA": "Активувати",
"vi-VN": "Kích hoạt",
"zh-CN": "启用",
},
"activated": {
"de-DE": "Aktiviert",
@ -194,6 +209,7 @@ const Translations = {
"tr-TR": "Etkin",
"uk-UA": "Активований",
"vi-VN": "Đã kích hoạt",
"zh-CN": "已启用",
},
"active": {
"de-DE": "Aktiv",
@ -235,6 +251,7 @@ const Translations = {
"tr-TR": "Uygula",
"uk-UA": "Застосувати",
"vi-VN": "Áp dụng",
"zh-CN": "应用",
},
"audio": {
"de-DE": "Audio",
@ -425,7 +442,7 @@ const Translations = {
"ru-RU": "Яркость",
"tr-TR": "Aydınlık",
"uk-UA": "Яскравість",
"vi-VN": ộ sáng",
"vi-VN": ộ sáng",
"zh-CN": "亮度",
},
"browser-unsupported-feature": {
@ -531,7 +548,7 @@ const Translations = {
"ru-RU": "Очистить",
"tr-TR": "Temizle",
"uk-UA": "Очистити",
"vi-VN": "Xóa",
"vi-VN": "Xa",
"zh-CN": "清空",
},
"close": {
@ -668,6 +685,7 @@ const Translations = {
"tr-TR": "Kopyala",
"uk-UA": "Копіювати",
"vi-VN": "Sao chép",
"zh-CN": "复制",
},
"custom": {
"de-DE": "Benutzerdefiniert",
@ -936,7 +954,7 @@ const Translations = {
"ru-RU": "Включить функцию «Удаленная игра»",
"tr-TR": "\"Uzaktan Oynama\" özelliğini aktive et",
"uk-UA": "Увімкнути функцію \"Remote Play\"",
"vi-VN": "Bật tính năng \"Chơi txa\"",
"vi-VN": "Bật tính năng \"Chơi TXa\"",
"zh-CN": "启用\"远程播放\"功能",
},
"enable-volume-control": {
@ -1016,10 +1034,13 @@ const Translations = {
"help": {
"de-DE": "Hilfe",
"en-US": "Help",
"es-ES": "Ayuda",
"ja-JP": "ヘルプ",
"pt-BR": "Ajuda",
"ru-RU": "Справка",
"uk-UA": "Довідка",
"vi-VN": "Trợ giúp",
"zh-CN": "帮助",
},
"hide-idle-cursor": {
"de-DE": "Mauszeiger bei Inaktivität ausblenden",
@ -1064,6 +1085,7 @@ const Translations = {
"tr-TR": "Yatay hassasiyet",
"uk-UA": "Горизонтальна чутливість",
"vi-VN": "Độ nhạy ngang",
"zh-CN": "水平灵敏度",
},
"import": {
"de-DE": "Importieren",
@ -1138,6 +1160,7 @@ const Translations = {
"tr-TR": "Sol analog çubuk",
"uk-UA": "Лівий стік",
"vi-VN": "Analog trái",
"zh-CN": "左摇杆",
},
"loading-screen": {
"de-DE": "Ladebildschirm",
@ -1208,7 +1231,7 @@ const Translations = {
"ko-KR": "통계",
"pl-PL": "Statystyki strumienia",
"pt-BR": "Estatísticas da transmissão",
"ru-RU": "Статистика потоковой передачи",
"ru-RU": "Статистика стрима",
"tr-TR": "Yayın durumu",
"uk-UA": "Статистика трансляції",
"vi-VN": "Thông số stream",
@ -1250,6 +1273,7 @@ const Translations = {
"tr-TR": "Etkinleştirmek için tıklayın",
"uk-UA": "Натисніть, щоб активувати",
"vi-VN": "Nhấn vào để kích hoạt",
"zh-CN": "单击以启用",
},
"mouse-and-keyboard": {
"de-DE": "Maus & Tastatur",
@ -1307,6 +1331,7 @@ const Translations = {
"tr-TR": "Yeni",
"uk-UA": "Новий",
"vi-VN": "Tạo mới",
"zh-CN": "新建",
},
"no-consoles-found": {
"de-DE": "Keine Konsolen gefunden",
@ -1638,7 +1663,7 @@ const Translations = {
"ru-RU": "Удаленная игра",
"tr-TR": "Uzaktan Bağlanma",
"uk-UA": "Віддалена гра",
"vi-VN": "Chơi txa",
"vi-VN": "Chơi TXa",
"zh-CN": "远程游玩",
},
"rename": {
@ -1653,6 +1678,7 @@ const Translations = {
"tr-TR": "Ad değiştir",
"uk-UA": "Перейменувати",
"vi-VN": "Sửa tên",
"zh-CN": "重命名",
},
"right-click-to-unbind": {
"de-DE": "Rechtsklick auf Taste: Zuordnung aufheben",
@ -1678,6 +1704,7 @@ const Translations = {
"tr-TR": "Sağ analog çubuk",
"uk-UA": "Правий стік",
"vi-VN": "Analog phải",
"zh-CN": "右摇杆",
},
"rocket-always-hide": {
"de-DE": "Immer ausblenden",
@ -2128,6 +2155,7 @@ const Translations = {
"pt-BR": "Mínimo decaimento do analógico",
"ru-RU": "Минимальная перезарядка стика",
"tr-TR": "Çubuğun ortalanma süresi minimumu",
"uk-UA": "Мінімальне згасання стіка",
"vi-VN": "Độ suy giảm tối thiểu của cần điều khiển",
},
"stick-decay-strength": {
@ -2137,6 +2165,7 @@ const Translations = {
"pt-BR": "Força de decaimento do analógico",
"ru-RU": "Скорость перезарядки стика",
"tr-TR": "Çubuğun ortalanma gücü",
"uk-UA": "Сила згасання стіка",
"vi-VN": "Sức mạnh độ suy giảm của cần điều khiển",
},
"stream": {
@ -2180,7 +2209,8 @@ const Translations = {
"ru-RU": "Поддержать Better xCloud",
"tr-TR": "Better xCloud'a destek ver",
"uk-UA": "Підтримати Better xCloud",
"vi-VN": "Hỗ trợ Better xCloud",
"vi-VN": "Ủng hộ Better xCloud",
"zh-CN": "赞助本插件",
},
"swap-buttons": {
"de-DE": "Tasten tauschen",
@ -2506,6 +2536,7 @@ const Translations = {
"tr-TR": "Dikey hassasiyet",
"uk-UA": "Вертикальна чутливість",
"vi-VN": "Độ ngạy dọc",
"zh-CN": "垂直灵敏度",
},
"vibration-intensity": {
"de-DE": "Vibrationsstärke",
@ -2760,7 +2791,12 @@ class Dialog {
this.onClose = onClose;
this.$dialog = CE('div', {'class': `bx-dialog ${className || ''} bx-gone`},
this.$title = CE('h2', {}, CE('b', {}, title),
helpUrl && createButton({icon: Icon.QUESTION, isGhost: true, title: __('help'), url: helpUrl}),
helpUrl && createButton({
icon: Icon.QUESTION,
style: ButtonStyle.GHOST,
title: __('help'),
url: helpUrl,
}),
),
this.$content = CE('div', {'class': 'bx-dialog-content'}, content),
!hideCloseButton && ($close = CE('button', {}, __('close'))),
@ -2780,6 +2816,9 @@ class Dialog {
}
show(newOptions) {
// Clear focus
document.activeElement && document.activeElement.blur();
if (newOptions && newOptions.title) {
this.$title.querySelector('b').textContent = newOptions.title;
this.$title.classList.remove('bx-gone');
@ -2929,34 +2968,40 @@ class RemotePlay {
CE('div', {'class': 'bx-remote-play-device-info'},
CE('div', {},
CE('span', {'class': 'bx-remote-play-device-name'}, con.deviceName),
CE('span', {'class': 'bx-remote-play-console-type'}, con.consoleType)
CE('span', {'class': 'bx-remote-play-console-type'}, con.consoleType.replace('Xbox', ''))
),
CE('div', {'class': 'bx-remote-play-power-state'}, RemotePlay.#STATE_LABELS[con.powerState]),
),
$connectButton = CE('button', {'class': 'bx-primary-button bx-no-margin'}, __('console-connect')),
// Connect button
createButton({
classes: ['bx-remote-play-connect-button'],
label: __('console-connect'),
style: ButtonStyle.PRIMARY,
onClick: e => {
REMOTE_PLAY_CONFIG = {
serverId: con.serverId,
};
window.BX_REMOTE_PLAY_CONFIG = REMOTE_PLAY_CONFIG;
const url = window.location.href.substring(0, 31) + '/launch/fortnite/BT5P2X999VH2#remote-play';
const $pageContent = document.getElementById('PageContent');
const $anchor = CE('a', { href: url, class: 'bx-hidden bx-offscreen' }, '');
$anchor.addEventListener('click', e => {
setTimeout(() => {
$pageContent.removeChild($anchor);
}, 1000);
});
$pageContent.appendChild($anchor);
$anchor.click();
RemotePlay.#dialog.hide();
},
}),
);
$connectButton.addEventListener('click', e => {
REMOTE_PLAY_CONFIG = {
serverId: con.serverId,
};
window.BX_REMOTE_PLAY_CONFIG = REMOTE_PLAY_CONFIG;
const url = window.location.href.substring(0, 31) + '/launch/fortnite/BT5P2X999VH2#remote-play';
const $pageContent = document.getElementById('PageContent');
const $anchor = CE('a', {href: url, class: 'bx-hidden', style: 'position:absolute;top:-9990px;left:-9999px'}, '');
$anchor.addEventListener('click', e => {
setTimeout(() => {
$pageContent.removeChild($anchor);
}, 1000);
});
$pageContent.appendChild($anchor);
$anchor.click();
RemotePlay.#dialog.hide();
});
$fragment.appendChild($child);
}
@ -4276,7 +4321,7 @@ class MkbHandler {
value = (buttonIndex === GamepadKey.RS_LEFT || buttonIndex === GamepadKey.RS_UP) ? -1 : 1;
}
virtualGamepad.axes[axisIndex] = pressed ? value : 0;
virtualGamepad.axes[axisIndex] += pressed ? value : - value;
} else {
virtualGamepad.buttons[buttonIndex].pressed = pressed;
virtualGamepad.buttons[buttonIndex].value = pressed ? 1 : 0;
@ -4300,6 +4345,11 @@ class MkbHandler {
return;
}
// Ignore repeating keys
if (e.repeat) {
return;
}
e.preventDefault();
this.#pressButton(buttonIndex, isKeyDown);
}
@ -4943,7 +4993,7 @@ class MkbRemapper {
// Delete button
createButton({
icon: Icon.TRASH,
isDanger: true,
style: ButtonStyle.DANGER,
title: __('delete'),
onClick: e => {
if (!confirm(__('confirm-delete-preset'))) {
@ -5029,7 +5079,7 @@ class MkbRemapper {
// Activate button
this.#$.activateButton = createButton({
label: __('activate'),
isPrimary: true,
style: ButtonStyle.PRIMARY,
onClick: e => {
PREFS.set(Preferences.MKB_DEFAULT_PRESET_ID, this.#STATE.currentPresetId);
MkbHandler.INSTANCE.refreshPresetData();
@ -5043,7 +5093,7 @@ class MkbRemapper {
// Cancel button
createButton({
label: __('cancel'),
isGhost: true,
style: ButtonStyle.GHOST,
onClick: e => {
// Restore preset
this.#switchPreset(this.#STATE.currentPresetId);
@ -5054,7 +5104,7 @@ class MkbRemapper {
// Save button
createButton({
label: __('save'),
isPrimary: true,
style: ButtonStyle.PRIMARY,
onClick: e => {
const updatedPreset = structuredClone(this.#getCurrentPreset());
updatedPreset.data = this.#STATE.editingPresetData;
@ -5724,13 +5774,13 @@ class StreamStats {
const packetsLost = stat.packetsLost;
const packetsReceived = stat.packetsReceived;
const packetsLostPercentage = (packetsLost * 100 / ((packetsLost + packetsReceived) || 1)).toFixed(2);
StreamStats.#$pl.textContent = `${packetsLost} (${packetsLostPercentage}%)`;
StreamStats.#$pl.textContent = packetsLostPercentage === '0.00' ? packetsLost : `${packetsLost} (${packetsLostPercentage}%)`;
// Frames Dropped
const framesDropped = stat.framesDropped;
const framesReceived = stat.framesReceived;
const framesDroppedPercentage = (framesDropped * 100 / ((framesDropped + framesReceived) || 1)).toFixed(2);
StreamStats.#$fl.textContent = `${framesDropped} (${framesDroppedPercentage}%)`;
StreamStats.#$fl.textContent = framesDroppedPercentage === '0.00' ? framesDropped : `${framesDropped} (${framesDroppedPercentage}%)`;
if (StreamStats.#lastStat) {
const lastStat = StreamStats.#lastStat;
@ -5793,17 +5843,17 @@ class StreamStats {
}
const STATS = {
[StreamStats.PING]: (StreamStats.#$ping = CE('span', {}, '0')),
[StreamStats.FPS]: (StreamStats.#$fps = CE('span', {}, '0')),
[StreamStats.BITRATE]: (StreamStats.#$br = CE('span', {}, '0 Mbps')),
[StreamStats.DECODE_TIME]: (StreamStats.#$dt = CE('span', {}, '0ms')),
[StreamStats.PACKETS_LOST]: (StreamStats.#$pl = CE('span', {}, '0 (0.00%)')),
[StreamStats.FRAMES_LOST]: (StreamStats.#$fl = CE('span', {}, '0 (0.00%)')),
[StreamStats.PING]: [__('stat-ping'), StreamStats.#$ping = CE('span', {}, '0')],
[StreamStats.FPS]: [__('stat-fps'), StreamStats.#$fps = CE('span', {}, '0')],
[StreamStats.BITRATE]: [__('stat-bitrate'), StreamStats.#$br = CE('span', {}, '0 Mbps')],
[StreamStats.DECODE_TIME]: [__('stat-decode-time'), StreamStats.#$dt = CE('span', {}, '0ms')],
[StreamStats.PACKETS_LOST]: [__('stat-packets-lost'), StreamStats.#$pl = CE('span', {}, '0')],
[StreamStats.FRAMES_LOST]: [__('stat-frames-lost'), StreamStats.#$fl = CE('span', {}, '0')],
};
const $barFragment = document.createDocumentFragment();
for (let statKey in STATS) {
const $div = CE('div', {'class': `bx-stat-${statKey}`}, CE('label', {}, statKey.toUpperCase()), STATS[statKey]);
const $div = CE('div', {'class': `bx-stat-${statKey}`, title: STATS[statKey][0]}, CE('label', {}, statKey.toUpperCase()), STATS[statKey][1]);
$barFragment.appendChild($div);
}
@ -6827,7 +6877,7 @@ if (window.BX_VIBRATION_INTENSITY && window.BX_VIBRATION_INTENSITY < 1) {
const nativeBind = Function.prototype.bind;
Function.prototype.bind = function() {
let valid = false;
if (arguments.length === 2 && arguments[0] === null) {
if (this.name.length <= 2 && arguments.length === 2 && arguments[0] === null) {
if (arguments[1] === 0 || (typeof arguments[1] === 'function')) {
valid = true;
}
@ -7040,6 +7090,8 @@ function addCss() {
--bx-monospaced-font: Consolas, "Courier New", Courier, monospace;
--bx-promptfont-font: promptfont;
--bx-button-height: 36px;
--bx-default-button-color: #2d3036;
--bx-default-button-hover-color: #515863;
--bx-default-button-disabled-color: #8e8e8e;
@ -7090,11 +7142,12 @@ a.bx-button {
font-size: 14px;
border: none;
font-weight: 400;
height: 32px;
height: var(--bx-button-height);
border-radius: 4px;
padding: 0 8px;
text-transform: uppercase;
cursor: pointer;
overflow: hidden;
}
.bx-button:hover, .bx-button.bx-focusable:focus {
@ -7141,7 +7194,7 @@ a.bx-button {
.bx-button svg {
display: inline-block;
width: 16px;
height: 32px;
height: var(--bx-button-height);
}
.bx-button svg:not(:only-child) {
@ -7150,10 +7203,12 @@ a.bx-button {
.bx-button span {
display: inline-block;
height: 30px;
line-height: 32px;
height: calc(var(--bx-button-height) - 2px);
line-height: var(--bx-button-height);
vertical-align: middle;
color: #fff;
overflow: hidden;
white-space: nowrap;
}
.bx-remote-play-button {
@ -7162,29 +7217,39 @@ a.bx-button {
}
.bx-remote-play-button svg {
width: 32px;
width: 28px;
height: 46px;
}
.bx-settings-button {
background-color: transparent;
border: none;
color: white;
font-weight: bold;
line-height: 30px;
border-radius: 4px;
padding: 8px;
font-size: 14px;
}
.bx-settings-button:hover, .bx-settings-button:focus {
background-color: #515863;
text-transform: none;
}
.bx-settings-button[data-update-available]::after {
content: ' 🌟';
}
.bx-remote-play-button, .bx-settings-button {
position: relative;
}
.bx-remote-play-button::after, .bx-settings-button::after {
border: 2px solid transparent;
border-radius: 4px;
}
.bx-remote-play-button:focus::after, .bx-settings-button:focus::after {
content: '';
border-color: white;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.better_xcloud_settings {
background-color: #151515;
user-select: none;
@ -7197,6 +7262,10 @@ a.bx-button {
width: 100% !important;
}
.bx-full-height {
height: 100% !important;
}
.bx-no-scroll {
overflow: hidden !important;
}
@ -7230,6 +7299,12 @@ a.bx-button {
padding: 12px 6px;
}
@media screen and (max-width: 450px) {
.bx-settings-wrapper {
width: 100%;
}
}
.bx-settings-wrapper *:focus {
outline: none !important;
}
@ -7320,39 +7395,8 @@ a.bx-button {
align-self: center;
}
.bx-primary-button {
padding: 8px 32px;
margin: 10px auto 0;
border: none;
border-radius: 4px;
display: block;
background-color: #044e2a;
text-align: center;
color: white;
text-transform: uppercase;
font-family: var(--bx-title-font);
font-weight: 400;
font-size: 14px;
line-height: 24px;
}
@media (hover: hover) {
.bx-primary-button:hover {
background-color: #00753c;
}
}
.bx-primary-button:focus {
background-color: #00753c;
}
.bx-primary-button:active {
background-color: #00753c;
}
.bx-primary-button[disabled] {
background: #393939;
color: #a2a2a2;
.bx-settings-wrapper .bx-button.bx-primary {
margin-top: 8px;
}
.bx-settings-app-version {
@ -7480,6 +7524,7 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
margin-right: 8px;
border-right: 1px solid #fff;
padding-right: 8px;
cursor: help;
}
.bx-stats-bar[data-stats*="[fps]"] > .bx-stat-fps,
@ -7533,6 +7578,7 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
font-size: inherit;
font-weight: bold;
vertical-align: middle;
cursor: help;
}
.bx-stats-bar span {
@ -7593,6 +7639,12 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
outline: none !important;
}
@media screen and (max-width: 450px) {
.bx-dialog {
min-width: 100%;
}
}
.bx-dialog h2 {
display: flex;
margin-bottom: 12px;
@ -7605,7 +7657,7 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
font-family: var(--bx-title-font);
font-size: 26px;
font-weight: 400;
line-height: 32px;
line-height: var(--bx-button-height);
}
.bx-dialog.bx-binding-dialog h2 b {
@ -7766,16 +7818,16 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
.bx-quick-settings-tab-contents h2 span {
display: inline-block;
font-size: 28px;
font-size: 24px;
font-weight: bold;
text-transform: uppercase;
text-align: left;
flex: 1;
height: 32px;
line-height: 32px;
}
.bx-quick-settings-tab-contents h2 a {
height: var(--bx-button-height);
line-height: calc(var(--bx-button-height) + 4px);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.bx-quick-settings-tab-contents input[type="range"] {
@ -7882,7 +7934,8 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
display: flex;
flex-direction: column;
flex: 1;
overflow: scroll;
padding-bottom: 10px;
overflow: hidden;
}
.bx-mkb-settings select:disabled {
@ -7973,6 +8026,7 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
font-family: var(--bx-promptfont-font);
font-size: 26px;
text-align: center;
width: 26px;
height: 32px;
line-height: 32px;
}
@ -8154,7 +8208,7 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
.bx-remote-play-console-type {
font-size: 12px;
background: #888;
background: #004c87;
color: #fff;
display: inline-block;
border-radius: 14px;
@ -8168,6 +8222,11 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
font-size: 14px;
}
.bx-remote-play-connect-button {
min-height: 100%;
margin: 4px 0;
}
/* ----------- */
/* Hide UI elements */
@ -8830,38 +8889,45 @@ function injectSettingsButton($parent) {
const PREF_PREFERRED_REGION = getPreferredServerRegion();
const PREF_LATEST_VERSION = PREFS.get(Preferences.LATEST_VERSION);
const $headerFragment = document.createDocumentFragment();
// Remote Play button
if (PREFS.get(Preferences.REMOTE_PLAY_ENABLED)) {
const $remotePlayBtn = createButton({
classes: ['bx-remote-play-button'],
icon: Icon.REMOTE_PLAY,
title: __('remote-play'),
isGhost: true,
isRound: true,
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE,
onClick: e => {
RemotePlay.showDialog();
},
});
$remotePlayBtn.classList.add('bx-remote-play-button', 'bx-focusable');
$parent.appendChild($remotePlayBtn);
$headerFragment.appendChild($remotePlayBtn);
}
// Setup Settings button
const $button = CE('button', {'class': 'bx-settings-button'}, PREF_PREFERRED_REGION);
$button.addEventListener('click', e => {
const $settings = document.querySelector('.better_xcloud_settings');
$settings.classList.toggle('bx-gone');
$settings.scrollIntoView();
const $settingsBtn = createButton({
classes: ['bx-settings-button'],
label: PREF_PREFERRED_REGION,
style: ButtonStyle.GHOST | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_HEIGHT,
onClick: e => {
const $settings = document.querySelector('.better_xcloud_settings');
$settings.classList.toggle('bx-gone');
$settings.scrollIntoView();
document.activeElement && document.activeElement.blur();
},
});
// Show new update status
if (PREF_LATEST_VERSION && PREF_LATEST_VERSION !== SCRIPT_VERSION) {
$button.setAttribute('data-update-available', true);
$settingsBtn.setAttribute('data-update-available', true);
}
// Add Settings button to the web page
$parent.appendChild($button);
// Add the Settings button to the web page
$headerFragment.appendChild($settingsBtn);
$parent.appendChild($headerFragment);
// Setup Settings UI
const $container = CE('div', {
@ -8912,6 +8978,14 @@ function injectSettingsButton($parent) {
[Preferences.AUDIO_MIC_ON_PLAYING]: __('enable-mic-on-startup'),
[Preferences.STREAM_DISABLE_FEEDBACK_DIALOG]: __('disable-post-stream-feedback-dialog'),
},
[__('mouse-and-keyboard')]: {
// '_note': '⚠️ ' + __('may-not-work-properly'),
// [Preferences.MKB_ENABLED]: [__('enable-mkb'), __('only-supports-some-games')],
[Preferences.MKB_ENABLED]: __('enable-mkb'),
[Preferences.MKB_HIDE_IDLE_CURSOR]: __('hide-idle-cursor'),
},
/*
[__('controller')]: {
[Preferences.CONTROLLER_ENABLE_SHORTCUTS]: __('enable-controller-shortcuts'),
@ -8923,13 +8997,6 @@ function injectSettingsButton($parent) {
[Preferences.STREAM_TOUCH_CONTROLLER_STYLE_CUSTOM]: __('tc-custom-layout-style'),
},
[__('mouse-and-keyboard')]: {
// '_note': '⚠️ ' + __('may-not-work-properly'),
// [Preferences.MKB_ENABLED]: [__('enable-mkb'), __('only-supports-some-games')],
[Preferences.MKB_ENABLED]: __('enable-mkb'),
[Preferences.MKB_HIDE_IDLE_CURSOR]: __('hide-idle-cursor'),
},
[__('loading-screen')]: {
[Preferences.UI_LOADING_SCREEN_GAME_ART]: __('show-game-art'),
[Preferences.UI_LOADING_SCREEN_WAIT_TIME]: __('show-wait-time'),
@ -9074,11 +9141,17 @@ function injectSettingsButton($parent) {
}
// Setup Reload button
const $reloadBtn = CE('button', {'class': 'bx-primary-button bx-full-width', 'tabindex': 0}, __('settings-reload'));
$reloadBtn.addEventListener('click', e => {
window.location.reload();
$reloadBtn.textContent = __('settings-reloading');
const $reloadBtn = createButton({
classes: ['bx-settings-reload-button'],
label: __('settings-reload'),
style: ButtonStyle.PRIMARY | ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH,
onClick: e => {
window.location.reload();
$reloadBtn.disabled = true;
$reloadBtn.textContent = __('settings-reloading');
},
});
$reloadBtn.setAttribute('tabindex', 0);
$wrapper.appendChild($reloadBtn);
// Donation link
@ -9731,7 +9804,12 @@ function setupQuickSettingsBar() {
for (const settingGroup of settingTab.items) {
$group.appendChild(CE('h2', {},
CE('span', {}, settingGroup.label),
settingGroup.help_url && createButton({icon: Icon.QUESTION, isGhost: true, url: settingGroup.help_url, title: __('help')}),
settingGroup.help_url && createButton({
icon: Icon.QUESTION,
style: ButtonStyle.GHOST,
url: settingGroup.help_url,
title: __('help'),
}),
));
if (settingGroup.note) {
if (typeof settingGroup.note === 'string') {