mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-28 18:31:44 +02:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
83a8e1f847 | |||
5ccd04478d | |||
da2a3c87bc | |||
a8996fe3a5 | |||
89a5bbdd2e | |||
58f8f6e762 | |||
401f8def06 | |||
f560c225de | |||
d6b254b134 | |||
36a6259817 | |||
76947a39de | |||
151b87fb69 | |||
0a6bd5b763 | |||
477989d542 | |||
15eaf76042 | |||
a495d3147b | |||
2fb61c1c44 |
@ -1,5 +1,5 @@
|
||||
// ==UserScript==
|
||||
// @name Better xCloud
|
||||
// @namespace https://github.com/redphx
|
||||
// @version 3.0.2.1
|
||||
// @version 3.0.3
|
||||
// ==/UserScript==
|
||||
|
@ -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": "Xóa",
|
||||
"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 từ xa\"",
|
||||
"vi-VN": "Bật tính năng \"Chơi Từ Xa\"",
|
||||
"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 từ xa",
|
||||
"vi-VN": "Chơi Từ Xa",
|
||||
"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') {
|
||||
|
Reference in New Issue
Block a user