mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-07-03 12:51:43 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
4f3430c43c | |||
15c6d3c74b | |||
b170b95145 | |||
4217b89194 | |||
38211168e9 | |||
392dc2cf86 | |||
67de264aa9 | |||
3e2c1bb2a4 | |||
5653914d19 | |||
4a8f66f2a1 | |||
70f43ba8f2 | |||
4d49639622 | |||
22f1ebdd08 | |||
bae51eff3d | |||
adc9897210 | |||
53442557e1 | |||
5b67b4c37d | |||
5a06933143 | |||
6440c91cdf | |||
b06dc6e219 |
348
dist/better-xcloud.lite.user.js
vendored
348
dist/better-xcloud.lite.user.js
vendored
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud (Lite)
|
// @name Better xCloud (Lite)
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.9.0
|
// @version 5.9.3
|
||||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||||
// @author redphx
|
// @author redphx
|
||||||
// @license MIT
|
// @license MIT
|
||||||
@ -105,7 +105,7 @@ class UserAgent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var SCRIPT_VERSION = "5.9.0", SCRIPT_VARIANT = "lite", AppInterface = window.AppInterface;
|
var SCRIPT_VERSION = "5.9.3", SCRIPT_VARIANT = "lite", AppInterface = window.AppInterface;
|
||||||
UserAgent.init();
|
UserAgent.init();
|
||||||
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
||||||
supportedRegion: !0,
|
supportedRegion: !0,
|
||||||
@ -300,6 +300,11 @@ var SUPPORTED_LANGUAGES = {
|
|||||||
"confirm-reload-stream": "Do you want to refresh the stream?",
|
"confirm-reload-stream": "Do you want to refresh the stream?",
|
||||||
connected: "Connected",
|
connected: "Connected",
|
||||||
"console-connect": "Connect",
|
"console-connect": "Connect",
|
||||||
|
"continent-asia": "Asia",
|
||||||
|
"continent-australia": "Australia",
|
||||||
|
"continent-europe": "Europe",
|
||||||
|
"continent-north-america": "North America",
|
||||||
|
"continent-south-america": "South America",
|
||||||
contrast: "Contrast",
|
contrast: "Contrast",
|
||||||
controller: "Controller",
|
controller: "Controller",
|
||||||
"controller-friendly-ui": "Controller-friendly UI",
|
"controller-friendly-ui": "Controller-friendly UI",
|
||||||
@ -403,7 +408,7 @@ var SUPPORTED_LANGUAGES = {
|
|||||||
e => `${e.version} 버전 사용가능`,
|
e => `${e.version} 버전 사용가능`,
|
||||||
e => `Dostępna jest nowa wersja ${e.version}`,
|
e => `Dostępna jest nowa wersja ${e.version}`,
|
||||||
e => `Versão ${e.version} disponível`,
|
e => `Versão ${e.version} disponível`,
|
||||||
,
|
e => `Версия ${e.version} доступна`,
|
||||||
e => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,
|
e => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,
|
||||||
e => `${e.version} sayılı yeni sürüm mevcut`,
|
e => `${e.version} sayılı yeni sürüm mevcut`,
|
||||||
e => `Доступна версія ${e.version}`,
|
e => `Доступна версія ${e.version}`,
|
||||||
@ -752,14 +757,16 @@ class SettingElement {
|
|||||||
}
|
}
|
||||||
static #renderNumberStepper(key, setting, value, onChange, options = {}) {
|
static #renderNumberStepper(key, setting, value, onChange, options = {}) {
|
||||||
options = options || {}, options.suffix = options.suffix || "", options.disabled = !!options.disabled, options.hideSlider = !!options.hideSlider;
|
options = options || {}, options.suffix = options.suffix || "", options.disabled = !!options.disabled, options.hideSlider = !!options.hideSlider;
|
||||||
let $text, $btnDec, $btnInc, $range = null, controlValue = value, MIN = options.reverse ? -setting.max : setting.min, MAX = options.reverse ? -setting.min : setting.max, STEPS = Math.max(setting.steps || 1, 1), renderTextValue = (value2) => {
|
let $text, $btnDec, $btnInc, $range = null, controlValue = value, MIN = options.reverse ? -setting.max : setting.min, MAX = options.reverse ? -setting.min : setting.max, STEPS = Math.max(setting.steps || 1, 1), intervalId, isHolding = !1, clearIntervalId = () => {
|
||||||
|
intervalId && clearInterval(intervalId), intervalId = null;
|
||||||
|
}, renderTextValue = (value2) => {
|
||||||
value2 = parseInt(value2);
|
value2 = parseInt(value2);
|
||||||
let textContent = null;
|
let textContent = null;
|
||||||
if (options.customTextValue) textContent = options.customTextValue(value2);
|
if (options.customTextValue) textContent = options.customTextValue(value2);
|
||||||
if (textContent === null) textContent = value2.toString() + options.suffix;
|
if (textContent === null) textContent = value2.toString() + options.suffix;
|
||||||
return textContent;
|
return textContent;
|
||||||
}, updateButtonsVisibility = () => {
|
}, updateButtonsVisibility = () => {
|
||||||
$btnDec.classList.toggle("bx-inactive", controlValue === MIN), $btnInc.classList.toggle("bx-inactive", controlValue === MAX);
|
if ($btnDec.classList.toggle("bx-inactive", controlValue === MIN), $btnInc.classList.toggle("bx-inactive", controlValue === MAX), controlValue === MIN || controlValue === MAX) clearIntervalId();
|
||||||
}, $wrapper = CE("div", { class: "bx-number-stepper", id: `bx_setting_${key}` }, $btnDec = CE("button", {
|
}, $wrapper = CE("div", { class: "bx-number-stepper", id: `bx_setting_${key}` }, $btnDec = CE("button", {
|
||||||
"data-type": "dec",
|
"data-type": "dec",
|
||||||
type: "button",
|
type: "button",
|
||||||
@ -773,7 +780,7 @@ class SettingElement {
|
|||||||
}, "+"));
|
}, "+"));
|
||||||
if (options.disabled) return $btnInc.disabled = !0, $btnInc.classList.add("bx-inactive"), $btnDec.disabled = !0, $btnDec.classList.add("bx-inactive"), $wrapper.disabled = !0, $wrapper;
|
if (options.disabled) return $btnInc.disabled = !0, $btnInc.classList.add("bx-inactive"), $btnDec.disabled = !0, $btnDec.classList.add("bx-inactive"), $wrapper.disabled = !0, $wrapper;
|
||||||
if ($range = CE("input", {
|
if ($range = CE("input", {
|
||||||
id: `bx_setting_${key}`,
|
id: `bx_inp_setting_${key}`,
|
||||||
type: "range",
|
type: "range",
|
||||||
min: MIN,
|
min: MIN,
|
||||||
max: MAX,
|
max: MAX,
|
||||||
@ -800,30 +807,29 @@ class SettingElement {
|
|||||||
$wrapper.appendChild($markers);
|
$wrapper.appendChild($markers);
|
||||||
}
|
}
|
||||||
updateButtonsVisibility();
|
updateButtonsVisibility();
|
||||||
let interval, isHolding = !1, onClick = (e) => {
|
let buttonPressed = (e, $btn) => {
|
||||||
if (isHolding) {
|
let value2 = parseInt(controlValue);
|
||||||
e.preventDefault(), isHolding = !1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let $btn = e.target, value2 = parseInt(controlValue);
|
|
||||||
if ($btn.dataset.type === "dec") value2 = Math.max(MIN, value2 - STEPS);
|
if ($btn.dataset.type === "dec") value2 = Math.max(MIN, value2 - STEPS);
|
||||||
else value2 = Math.min(MAX, value2 + STEPS);
|
else value2 = Math.min(MAX, value2 + STEPS);
|
||||||
controlValue = value2, updateButtonsVisibility(), $text.textContent = renderTextValue(value2), $range && ($range.value = value2.toString()), isHolding = !1, !e.ignoreOnChange && onChange && onChange(e, value2);
|
controlValue = value2, updateButtonsVisibility(), $text.textContent = renderTextValue(value2), $range && ($range.value = value2.toString()), onChange && onChange(e, value2);
|
||||||
}, onMouseDown = (e) => {
|
}, onClick = (e) => {
|
||||||
e.preventDefault(), isHolding = !0;
|
if (e.preventDefault(), isHolding) return;
|
||||||
let args = arguments;
|
let $btn = e.target.closest("button");
|
||||||
interval && clearInterval(interval), interval = window.setInterval(() => {
|
$btn && buttonPressed(e, $btn), clearIntervalId(), isHolding = !1;
|
||||||
e.target && BxEvent.dispatch(e.target, "click", {
|
}, onPointerDown = (e) => {
|
||||||
arguments: args
|
clearIntervalId();
|
||||||
});
|
let $btn = e.target.closest("button");
|
||||||
}, 200);
|
if (!$btn) return;
|
||||||
}, onMouseUp = (e) => {
|
isHolding = !0, e.preventDefault(), intervalId = window.setInterval((e2) => {
|
||||||
e.preventDefault(), interval && clearInterval(interval), isHolding = !1;
|
buttonPressed(e2, $btn);
|
||||||
|
}, 200), window.addEventListener("pointerup", onPointerUp, { once: !0 }), window.addEventListener("pointercancel", onPointerUp, { once: !0 });
|
||||||
|
}, onPointerUp = (e) => {
|
||||||
|
clearIntervalId(), isHolding = !1;
|
||||||
}, onContextMenu = (e) => e.preventDefault();
|
}, onContextMenu = (e) => e.preventDefault();
|
||||||
return $wrapper.setValue = (value2) => {
|
return $wrapper.setValue = (value2) => {
|
||||||
$text.textContent = renderTextValue(value2), $range.value = options.reverse ? -value2 : value2;
|
$text.textContent = renderTextValue(value2), $range.value = options.reverse ? -value2 : value2;
|
||||||
}, $btnDec.addEventListener("click", onClick), $btnDec.addEventListener("pointerdown", onMouseDown), $btnDec.addEventListener("pointerup", onMouseUp), $btnDec.addEventListener("contextmenu", onContextMenu), $btnInc.addEventListener("click", onClick), $btnInc.addEventListener("pointerdown", onMouseDown), $btnInc.addEventListener("pointerup", onMouseUp), $btnInc.addEventListener("contextmenu", onContextMenu), setNearby($wrapper, {
|
}, $wrapper.addEventListener("click", onClick), $wrapper.addEventListener("pointerdown", onPointerDown), $wrapper.addEventListener("contextmenu", onContextMenu), setNearby($wrapper, {
|
||||||
focus: $range || $btnInc
|
focus: options.hideSlider ? $btnInc : $range
|
||||||
}), $wrapper;
|
}), $wrapper;
|
||||||
}
|
}
|
||||||
static #METHOD_MAP = {
|
static #METHOD_MAP = {
|
||||||
@ -1393,7 +1399,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
|||||||
customTextValue(value) {
|
customTextValue(value) {
|
||||||
value = parseInt(value);
|
value = parseInt(value);
|
||||||
let text = +(1000 / value).toFixed(2) + " Hz";
|
let text = +(1000 / value).toFixed(2) + " Hz";
|
||||||
if (value === 4) text = `${t("default")} (${text})`;
|
if (value === 4) text = `${text} (${t("default")})`;
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2381,7 +2387,7 @@ class MouseDataProvider {
|
|||||||
class MkbHandler {}
|
class MkbHandler {}
|
||||||
class LocalDb {
|
class LocalDb {
|
||||||
static DB_NAME = "BetterXcloud";
|
static DB_NAME = "BetterXcloud";
|
||||||
static DB_VERSION = 1;
|
static DB_VERSION = 2;
|
||||||
db;
|
db;
|
||||||
open() {
|
open() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -2390,7 +2396,7 @@ class LocalDb {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let request = window.indexedDB.open(LocalDb.DB_NAME, LocalDb.DB_VERSION);
|
let request = window.indexedDB.open(LocalDb.DB_NAME, LocalDb.DB_VERSION);
|
||||||
request.onupgradeneeded = this.onUpgradeNeeded, request.onerror = (e) => {
|
request.onupgradeneeded = this.onUpgradeNeeded.bind(this), request.onerror = (e) => {
|
||||||
console.log(e), alert(e.target.error.message), reject && reject();
|
console.log(e), alert(e.target.error.message), reject && reject();
|
||||||
}, request.onsuccess = (e) => {
|
}, request.onsuccess = (e) => {
|
||||||
this.db = e.target.result, resolve();
|
this.db = e.target.result, resolve();
|
||||||
@ -2438,51 +2444,49 @@ class MkbPresetsDb extends LocalDb {
|
|||||||
super();
|
super();
|
||||||
BxLogger.info(this.LOG_TAG, "constructor()");
|
BxLogger.info(this.LOG_TAG, "constructor()");
|
||||||
}
|
}
|
||||||
|
createTable(db) {
|
||||||
|
db.createObjectStore(this.TABLE_PRESETS, {
|
||||||
|
keyPath: "id",
|
||||||
|
autoIncrement: !0
|
||||||
|
}).createIndex("name_idx", "name");
|
||||||
|
}
|
||||||
onUpgradeNeeded(e) {
|
onUpgradeNeeded(e) {
|
||||||
let db = e.target.result;
|
let db = e.target.result;
|
||||||
switch (e.oldVersion) {
|
if (db.objectStoreNames.contains("undefined")) db.deleteObjectStore("undefined");
|
||||||
case 0: {
|
if (!db.objectStoreNames.contains(this.TABLE_PRESETS)) this.createTable(db);
|
||||||
db.createObjectStore(this.TABLE_PRESETS, {
|
}
|
||||||
keyPath: "id",
|
async presetsTable() {
|
||||||
autoIncrement: !0
|
return await this.open(), await this.table(this.TABLE_PRESETS, "readwrite");
|
||||||
}).createIndex("name_idx", "name");
|
}
|
||||||
break;
|
async newPreset(name, data) {
|
||||||
}
|
let table = await this.presetsTable(), [, id] = await this.add(table, { name, data });
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
async updatePreset(preset) {
|
||||||
|
let table = await this.presetsTable(), [, id] = await this.put(table, preset);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
async deletePreset(id) {
|
||||||
|
let table = await this.presetsTable();
|
||||||
|
return await this.delete(table, id), id;
|
||||||
|
}
|
||||||
|
async getPreset(id) {
|
||||||
|
let table = await this.presetsTable(), [, preset] = await this.get(table, id);
|
||||||
|
return preset;
|
||||||
|
}
|
||||||
|
async getPresets() {
|
||||||
|
let table = await this.presetsTable(), [, count] = await this.count(table);
|
||||||
|
if (count > 0) {
|
||||||
|
let [, items] = await this.getAll(table), presets = {};
|
||||||
|
return items.forEach((item) => presets[item.id] = item), presets;
|
||||||
}
|
}
|
||||||
}
|
let preset = {
|
||||||
presetsTable() {
|
name: t("default"),
|
||||||
return this.open().then(() => this.table(this.TABLE_PRESETS, "readwrite"));
|
data: MkbPreset.DEFAULT_PRESET
|
||||||
}
|
}, [, id] = await this.add(table, preset);
|
||||||
newPreset(name, data) {
|
return preset.id = id, setPref("mkb_default_preset_id", id), {
|
||||||
return this.presetsTable().then((table) => this.add(table, { name, data })).then(([table, id]) => new Promise((resolve) => resolve(id)));
|
[id]: preset
|
||||||
}
|
};
|
||||||
updatePreset(preset) {
|
|
||||||
return this.presetsTable().then((table) => this.put(table, preset)).then(([table, id]) => new Promise((resolve) => resolve(id)));
|
|
||||||
}
|
|
||||||
deletePreset(id) {
|
|
||||||
return this.presetsTable().then((table) => this.delete(table, id)).then(([table, id2]) => new Promise((resolve) => resolve(id2)));
|
|
||||||
}
|
|
||||||
getPreset(id) {
|
|
||||||
return this.presetsTable().then((table) => this.get(table, id)).then(([table, preset]) => new Promise((resolve) => resolve(preset)));
|
|
||||||
}
|
|
||||||
getPresets() {
|
|
||||||
return this.presetsTable().then((table) => this.count(table)).then(([table, count]) => {
|
|
||||||
if (count > 0) return new Promise((resolve) => {
|
|
||||||
this.getAll(table).then(([table2, items]) => {
|
|
||||||
let presets = {};
|
|
||||||
items.forEach((item) => presets[item.id] = item), resolve(presets);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
let preset = {
|
|
||||||
name: t("default"),
|
|
||||||
data: MkbPreset.DEFAULT_PRESET
|
|
||||||
};
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.add(table, preset).then(([table2, id]) => {
|
|
||||||
preset.id = id, setPref("mkb_default_preset_id", id), resolve({ [id]: preset });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var PointerToMouseButton = {
|
var PointerToMouseButton = {
|
||||||
@ -2888,6 +2892,7 @@ class NavigationDialogManager {
|
|||||||
if (!width) return;
|
if (!width) return;
|
||||||
if ($select.multiple) $label = $parent.querySelector(".bx-select-value"), width += 20;
|
if ($select.multiple) $label = $parent.querySelector(".bx-select-value"), width += 20;
|
||||||
else $label = $parent.querySelector("div");
|
else $label = $parent.querySelector("div");
|
||||||
|
if ($select.querySelector("optgroup")) width -= 15;
|
||||||
$label.style.minWidth = width + "px", $parent.dataset.calculated = "true";
|
$label.style.minWidth = width + "px", $parent.dataset.calculated = "true";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2903,7 +2908,7 @@ class NavigationDialogManager {
|
|||||||
else if (keyCode === "ArrowLeft" || keyCode === "ArrowRight") {
|
else if (keyCode === "ArrowLeft" || keyCode === "ArrowRight") {
|
||||||
if (!($target instanceof HTMLInputElement && ($target.type === "text" || $target.type === "range"))) handled = !0, this.focusDirection(keyCode === "ArrowLeft" ? 4 : 2);
|
if (!($target instanceof HTMLInputElement && ($target.type === "text" || $target.type === "range"))) handled = !0, this.focusDirection(keyCode === "ArrowLeft" ? 4 : 2);
|
||||||
} else if (keyCode === "Enter" || keyCode === "NumpadEnter" || keyCode === "Space") {
|
} else if (keyCode === "Enter" || keyCode === "NumpadEnter" || keyCode === "Space") {
|
||||||
if (!($target instanceof HTMLInputElement && $target.type === "text")) handled = !0, $target.dispatchEvent(new MouseEvent("click"));
|
if (!($target instanceof HTMLInputElement && $target.type === "text")) handled = !0, $target.dispatchEvent(new MouseEvent("click", { bubbles: !0 }));
|
||||||
} else if (keyCode === "Escape") handled = !0, this.hide();
|
} else if (keyCode === "Escape") handled = !0, this.hide();
|
||||||
if (handled) event.preventDefault(), event.stopPropagation();
|
if (handled) event.preventDefault(), event.stopPropagation();
|
||||||
break;
|
break;
|
||||||
@ -2957,7 +2962,7 @@ class NavigationDialogManager {
|
|||||||
}
|
}
|
||||||
if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return;
|
if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return;
|
||||||
if (releasedButton === 0) {
|
if (releasedButton === 0) {
|
||||||
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent("click"));
|
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent("click", { bubbles: !0 }));
|
||||||
return;
|
return;
|
||||||
} else if (releasedButton === 1) {
|
} else if (releasedButton === 1) {
|
||||||
this.hide();
|
this.hide();
|
||||||
@ -3176,7 +3181,7 @@ class MkbRemapper {
|
|||||||
static instance;
|
static instance;
|
||||||
static getInstance = () => MkbRemapper.instance ?? (MkbRemapper.instance = new MkbRemapper);
|
static getInstance = () => MkbRemapper.instance ?? (MkbRemapper.instance = new MkbRemapper);
|
||||||
LOG_TAG = "MkbRemapper";
|
LOG_TAG = "MkbRemapper";
|
||||||
STATE = {
|
states = {
|
||||||
currentPresetId: 0,
|
currentPresetId: 0,
|
||||||
presets: {},
|
presets: {},
|
||||||
editingPresetData: null,
|
editingPresetData: null,
|
||||||
@ -3190,7 +3195,7 @@ class MkbRemapper {
|
|||||||
allMouseElements = {};
|
allMouseElements = {};
|
||||||
bindingDialog;
|
bindingDialog;
|
||||||
constructor() {
|
constructor() {
|
||||||
BxLogger.info(this.LOG_TAG, "constructor()"), this.STATE.currentPresetId = getPref("mkb_default_preset_id"), this.bindingDialog = new Dialog({
|
BxLogger.info(this.LOG_TAG, "constructor()"), this.states.currentPresetId = getPref("mkb_default_preset_id"), this.bindingDialog = new Dialog({
|
||||||
className: "bx-binding-dialog",
|
className: "bx-binding-dialog",
|
||||||
content: CE("div", {}, CE("p", {}, t("press-to-bind")), CE("i", {}, t("press-esc-to-cancel"))),
|
content: CE("div", {}, CE("p", {}, t("press-to-bind")), CE("i", {}, t("press-esc-to-cancel"))),
|
||||||
hideCloseButton: !0
|
hideCloseButton: !0
|
||||||
@ -3204,11 +3209,11 @@ class MkbRemapper {
|
|||||||
if ($elm.dataset.keyCode === key.code) return;
|
if ($elm.dataset.keyCode === key.code) return;
|
||||||
for (let $otherElm of this.allKeyElements)
|
for (let $otherElm of this.allKeyElements)
|
||||||
if ($otherElm.dataset.keyCode === key.code) this.unbindKey($otherElm);
|
if ($otherElm.dataset.keyCode === key.code) this.unbindKey($otherElm);
|
||||||
this.STATE.editingPresetData.mapping[buttonIndex][keySlot] = key.code, $elm.textContent = key.name, $elm.dataset.keyCode = key.code;
|
this.states.editingPresetData.mapping[buttonIndex][keySlot] = key.code, $elm.textContent = key.name, $elm.dataset.keyCode = key.code;
|
||||||
};
|
};
|
||||||
unbindKey = ($elm) => {
|
unbindKey = ($elm) => {
|
||||||
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot);
|
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot);
|
||||||
this.STATE.editingPresetData.mapping[buttonIndex][keySlot] = null, $elm.textContent = "", delete $elm.dataset.keyCode;
|
this.states.editingPresetData.mapping[buttonIndex][keySlot] = null, $elm.textContent = "", delete $elm.dataset.keyCode;
|
||||||
};
|
};
|
||||||
onWheel = (e) => {
|
onWheel = (e) => {
|
||||||
e.preventDefault(), this.clearEventListeners(), this.bindKey(this.$currentBindingKey, KeyHelper.getKeyFromEvent(e)), window.setTimeout(() => this.bindingDialog.hide(), 200);
|
e.preventDefault(), this.clearEventListeners(), this.bindKey(this.$currentBindingKey, KeyHelper.getKeyFromEvent(e)), window.setTimeout(() => this.bindingDialog.hide(), 200);
|
||||||
@ -3221,21 +3226,26 @@ class MkbRemapper {
|
|||||||
window.setTimeout(() => this.bindingDialog.hide(), 200);
|
window.setTimeout(() => this.bindingDialog.hide(), 200);
|
||||||
};
|
};
|
||||||
onBindingKey = (e) => {
|
onBindingKey = (e) => {
|
||||||
if (!this.STATE.isEditing || e.button !== 0) return;
|
if (!this.states.isEditing || e.button !== 0) return;
|
||||||
console.log(e), this.$currentBindingKey = e.target, window.addEventListener("keydown", this.onKeyDown), window.addEventListener("mousedown", this.onMouseDown), window.addEventListener("wheel", this.onWheel), this.bindingDialog.show({ title: this.$currentBindingKey.dataset.prompt });
|
console.log(e), this.$currentBindingKey = e.target, window.addEventListener("keydown", this.onKeyDown), window.addEventListener("mousedown", this.onMouseDown), window.addEventListener("wheel", this.onWheel), this.bindingDialog.show({ title: this.$currentBindingKey.dataset.prompt });
|
||||||
};
|
};
|
||||||
onContextMenu = (e) => {
|
onContextMenu = (e) => {
|
||||||
if (e.preventDefault(), !this.STATE.isEditing) return;
|
if (e.preventDefault(), !this.states.isEditing) return;
|
||||||
this.unbindKey(e.target);
|
this.unbindKey(e.target);
|
||||||
};
|
};
|
||||||
getPreset = (presetId) => {
|
getPreset = (presetId) => {
|
||||||
return this.STATE.presets[presetId];
|
return this.states.presets[presetId];
|
||||||
};
|
};
|
||||||
getCurrentPreset = () => {
|
getCurrentPreset = () => {
|
||||||
return this.getPreset(this.STATE.currentPresetId);
|
let preset = this.getPreset(this.states.currentPresetId);
|
||||||
|
if (!preset) {
|
||||||
|
let firstPresetId = parseInt(Object.keys(this.states.presets)[0]);
|
||||||
|
preset = this.states.presets[firstPresetId], this.states.currentPresetId = firstPresetId, setPref("mkb_default_preset_id", firstPresetId);
|
||||||
|
}
|
||||||
|
return preset;
|
||||||
};
|
};
|
||||||
switchPreset = (presetId) => {
|
switchPreset = (presetId) => {
|
||||||
this.STATE.currentPresetId = presetId;
|
this.states.currentPresetId = presetId;
|
||||||
let presetData = this.getCurrentPreset().data;
|
let presetData = this.getCurrentPreset().data;
|
||||||
for (let $elm of this.allKeyElements) {
|
for (let $elm of this.allKeyElements) {
|
||||||
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot), buttonKeys = presetData.mapping[buttonIndex];
|
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot), buttonKeys = presetData.mapping[buttonIndex];
|
||||||
@ -3248,35 +3258,33 @@ class MkbRemapper {
|
|||||||
if (typeof value === "undefined") value = MkbPreset.MOUSE_SETTINGS[key].default;
|
if (typeof value === "undefined") value = MkbPreset.MOUSE_SETTINGS[key].default;
|
||||||
"setValue" in $elm && $elm.setValue(value);
|
"setValue" in $elm && $elm.setValue(value);
|
||||||
}
|
}
|
||||||
let activated = getPref("mkb_default_preset_id") === this.STATE.currentPresetId;
|
let activated = getPref("mkb_default_preset_id") === this.states.currentPresetId;
|
||||||
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate");
|
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate");
|
||||||
};
|
};
|
||||||
refresh() {
|
async refresh() {
|
||||||
while (this.$presetsSelect.firstChild)
|
removeChildElements(this.$presetsSelect);
|
||||||
this.$presetsSelect.removeChild(this.$presetsSelect.firstChild);
|
let presets = await MkbPresetsDb.getInstance().getPresets();
|
||||||
MkbPresetsDb.getInstance().getPresets().then((presets) => {
|
this.states.presets = presets;
|
||||||
this.STATE.presets = presets;
|
let fragment = document.createDocumentFragment(), defaultPresetId;
|
||||||
let $fragment = document.createDocumentFragment(), defaultPresetId;
|
if (this.states.currentPresetId === 0) this.states.currentPresetId = parseInt(Object.keys(presets)[0]), defaultPresetId = this.states.currentPresetId, setPref("mkb_default_preset_id", defaultPresetId), EmulatedMkbHandler.getInstance().refreshPresetData();
|
||||||
if (this.STATE.currentPresetId === 0) this.STATE.currentPresetId = parseInt(Object.keys(presets)[0]), defaultPresetId = this.STATE.currentPresetId, setPref("mkb_default_preset_id", defaultPresetId), EmulatedMkbHandler.getInstance().refreshPresetData();
|
else defaultPresetId = getPref("mkb_default_preset_id");
|
||||||
else defaultPresetId = getPref("mkb_default_preset_id");
|
for (let id in presets) {
|
||||||
for (let id in presets) {
|
let name = presets[id].name;
|
||||||
let name = presets[id].name;
|
if (id === defaultPresetId) name = "🎮 " + name;
|
||||||
if (id === defaultPresetId) name = "🎮 " + name;
|
let $options = CE("option", { value: id }, name);
|
||||||
let $options = CE("option", { value: id }, name);
|
$options.selected = parseInt(id) === this.states.currentPresetId, fragment.appendChild($options);
|
||||||
$options.selected = parseInt(id) === this.STATE.currentPresetId, $fragment.appendChild($options);
|
}
|
||||||
}
|
this.$presetsSelect.appendChild(fragment);
|
||||||
this.$presetsSelect.appendChild($fragment);
|
let activated = defaultPresetId === this.states.currentPresetId;
|
||||||
let activated = defaultPresetId === this.STATE.currentPresetId;
|
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate"), !this.states.isEditing && this.switchPreset(this.states.currentPresetId);
|
||||||
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate"), !this.STATE.isEditing && this.switchPreset(this.STATE.currentPresetId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
toggleEditing = (force) => {
|
toggleEditing = (force) => {
|
||||||
if (this.STATE.isEditing = typeof force !== "undefined" ? force : !this.STATE.isEditing, this.$wrapper.classList.toggle("bx-editing", this.STATE.isEditing), this.STATE.isEditing) this.STATE.editingPresetData = deepClone(this.getCurrentPreset().data);
|
if (this.states.isEditing = typeof force !== "undefined" ? force : !this.states.isEditing, this.$wrapper.classList.toggle("bx-editing", this.states.isEditing), this.states.isEditing) this.states.editingPresetData = deepClone(this.getCurrentPreset().data);
|
||||||
else this.STATE.editingPresetData = null;
|
else this.states.editingPresetData = null;
|
||||||
let childElements = this.$wrapper.querySelectorAll("select, button, input");
|
let childElements = this.$wrapper.querySelectorAll("select, button, input");
|
||||||
for (let $elm of Array.from(childElements)) {
|
for (let $elm of Array.from(childElements)) {
|
||||||
if ($elm.parentElement.parentElement.classList.contains("bx-mkb-action-buttons")) continue;
|
if ($elm.parentElement.parentElement.classList.contains("bx-mkb-action-buttons")) continue;
|
||||||
let disable = !this.STATE.isEditing;
|
let disable = !this.states.isEditing;
|
||||||
if ($elm.parentElement.classList.contains("bx-mkb-preset-tools")) disable = !disable;
|
if ($elm.parentElement.classList.contains("bx-mkb-preset-tools")) disable = !disable;
|
||||||
$elm.disabled = disable;
|
$elm.disabled = disable;
|
||||||
}
|
}
|
||||||
@ -3296,10 +3304,10 @@ class MkbRemapper {
|
|||||||
title: t("rename"),
|
title: t("rename"),
|
||||||
icon: BxIcon.CURSOR_TEXT,
|
icon: BxIcon.CURSOR_TEXT,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: async () => {
|
||||||
let preset = this.getCurrentPreset(), newName = promptNewName(preset.name);
|
let preset = this.getCurrentPreset(), newName = promptNewName(preset.name);
|
||||||
if (!newName || newName === preset.name) return;
|
if (!newName || newName === preset.name) return;
|
||||||
preset.name = newName, MkbPresetsDb.getInstance().updatePreset(preset).then((id) => this.refresh());
|
preset.name = newName, await MkbPresetsDb.getInstance().updatePreset(preset), await this.refresh();
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
icon: BxIcon.NEW,
|
icon: BxIcon.NEW,
|
||||||
@ -3309,7 +3317,7 @@ class MkbRemapper {
|
|||||||
let newName = promptNewName("");
|
let newName = promptNewName("");
|
||||||
if (!newName) return;
|
if (!newName) return;
|
||||||
MkbPresetsDb.getInstance().newPreset(newName, MkbPreset.DEFAULT_PRESET).then((id) => {
|
MkbPresetsDb.getInstance().newPreset(newName, MkbPreset.DEFAULT_PRESET).then((id) => {
|
||||||
this.STATE.currentPresetId = id, this.refresh();
|
this.states.currentPresetId = id, this.refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
@ -3320,7 +3328,7 @@ class MkbRemapper {
|
|||||||
let preset = this.getCurrentPreset(), newName = promptNewName(`${preset.name} (2)`);
|
let preset = this.getCurrentPreset(), newName = promptNewName(`${preset.name} (2)`);
|
||||||
if (!newName) return;
|
if (!newName) return;
|
||||||
MkbPresetsDb.getInstance().newPreset(newName, preset.data).then((id) => {
|
MkbPresetsDb.getInstance().newPreset(newName, preset.data).then((id) => {
|
||||||
this.STATE.currentPresetId = id, this.refresh();
|
this.states.currentPresetId = id, this.refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
@ -3330,8 +3338,8 @@ class MkbRemapper {
|
|||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
if (!confirm(t("confirm-delete-preset"))) return;
|
if (!confirm(t("confirm-delete-preset"))) return;
|
||||||
MkbPresetsDb.getInstance().deletePreset(this.STATE.currentPresetId).then((id) => {
|
MkbPresetsDb.getInstance().deletePreset(this.states.currentPresetId).then((id) => {
|
||||||
this.STATE.currentPresetId = 0, this.refresh();
|
this.states.currentPresetId = 0, this.refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -3353,7 +3361,7 @@ class MkbRemapper {
|
|||||||
let $mouseSettings = document.createDocumentFragment();
|
let $mouseSettings = document.createDocumentFragment();
|
||||||
for (let key in MkbPreset.MOUSE_SETTINGS) {
|
for (let key in MkbPreset.MOUSE_SETTINGS) {
|
||||||
let setting = MkbPreset.MOUSE_SETTINGS[key], value = setting.default, $elm, onChange = (e, value2) => {
|
let setting = MkbPreset.MOUSE_SETTINGS[key], value = setting.default, $elm, onChange = (e, value2) => {
|
||||||
this.STATE.editingPresetData.mouse[key] = value2;
|
this.states.editingPresetData.mouse[key] = value2;
|
||||||
}, $row = CE("label", {
|
}, $row = CE("label", {
|
||||||
class: "bx-settings-row",
|
class: "bx-settings-row",
|
||||||
for: `bx_setting_${key}`
|
for: `bx_setting_${key}`
|
||||||
@ -3370,14 +3378,14 @@ class MkbRemapper {
|
|||||||
style: 1,
|
style: 1,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
setPref("mkb_default_preset_id", this.STATE.currentPresetId), EmulatedMkbHandler.getInstance().refreshPresetData(), this.refresh();
|
setPref("mkb_default_preset_id", this.states.currentPresetId), EmulatedMkbHandler.getInstance().refreshPresetData(), this.refresh();
|
||||||
}
|
}
|
||||||
})), CE("div", {}, createButton({
|
})), CE("div", {}, createButton({
|
||||||
label: t("cancel"),
|
label: t("cancel"),
|
||||||
style: 4,
|
style: 4,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
this.switchPreset(this.STATE.currentPresetId), this.toggleEditing(!1);
|
this.switchPreset(this.states.currentPresetId), this.toggleEditing(!1);
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
label: t("save"),
|
label: t("save"),
|
||||||
@ -3385,7 +3393,7 @@ class MkbRemapper {
|
|||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
let updatedPreset = deepClone(this.getCurrentPreset());
|
let updatedPreset = deepClone(this.getCurrentPreset());
|
||||||
updatedPreset.data = this.STATE.editingPresetData, MkbPresetsDb.getInstance().updatePreset(updatedPreset).then((id) => {
|
updatedPreset.data = this.states.editingPresetData, MkbPresetsDb.getInstance().updatePreset(updatedPreset).then((id) => {
|
||||||
if (id === getPref("mkb_default_preset_id")) EmulatedMkbHandler.getInstance().refreshPresetData();
|
if (id === getPref("mkb_default_preset_id")) EmulatedMkbHandler.getInstance().refreshPresetData();
|
||||||
this.toggleEditing(!1), this.refresh();
|
this.toggleEditing(!1), this.refresh();
|
||||||
});
|
});
|
||||||
@ -4098,26 +4106,52 @@ class SettingsNavigationDialog extends NavigationDialog {
|
|||||||
this.$btnReload.classList.add("bx-danger"), this.$noteGlobalReload.classList.add("bx-gone"), this.$btnGlobalReload.classList.remove("bx-gone"), this.$btnGlobalReload.classList.add("bx-danger");
|
this.$btnReload.classList.add("bx-danger"), this.$noteGlobalReload.classList.add("bx-gone"), this.$btnGlobalReload.classList.remove("bx-gone"), this.$btnGlobalReload.classList.add("bx-danger");
|
||||||
}
|
}
|
||||||
renderServerSetting(setting) {
|
renderServerSetting(setting) {
|
||||||
let selectedValue, $control = CE("select", {
|
let selectedValue = getPref("server_region"), continents = {
|
||||||
|
"america-north": {
|
||||||
|
label: t("continent-north-america")
|
||||||
|
},
|
||||||
|
"america-south": {
|
||||||
|
label: t("continent-south-america")
|
||||||
|
},
|
||||||
|
asia: {
|
||||||
|
label: t("continent-asia")
|
||||||
|
},
|
||||||
|
australia: {
|
||||||
|
label: t("continent-australia")
|
||||||
|
},
|
||||||
|
europe: {
|
||||||
|
label: t("continent-europe")
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
label: t("other")
|
||||||
|
}
|
||||||
|
}, $control = CE("select", {
|
||||||
id: `bx_setting_${setting.pref}`,
|
id: `bx_setting_${setting.pref}`,
|
||||||
title: setting.label,
|
title: setting.label,
|
||||||
tabindex: 0
|
tabindex: 0
|
||||||
});
|
});
|
||||||
$control.name = $control.id, $control.addEventListener("input", (e) => {
|
$control.name = $control.id, $control.addEventListener("input", (e) => {
|
||||||
setPref(setting.pref, e.target.value), this.onGlobalSettingChanged(e);
|
setPref(setting.pref, e.target.value), this.onGlobalSettingChanged(e);
|
||||||
}), selectedValue = getPref("server_region"), setting.options = {};
|
}), setting.options = {};
|
||||||
for (let regionName in STATES.serverRegions) {
|
for (let regionName in STATES.serverRegions) {
|
||||||
let region = STATES.serverRegions[regionName], value = regionName, label = `${region.shortName} - ${regionName}`;
|
let region = STATES.serverRegions[regionName], value = regionName, label = `${region.shortName} - ${regionName}`;
|
||||||
if (region.isDefault) {
|
if (region.isDefault) {
|
||||||
if (label += ` (${t("default")})`, value = "default", selectedValue === regionName) selectedValue = "default";
|
if (label += ` (${t("default")})`, value = "default", selectedValue === regionName) selectedValue = "default";
|
||||||
}
|
}
|
||||||
setting.options[value] = label;
|
setting.options[value] = label;
|
||||||
|
let $option = CE("option", { value }, label), continent = continents[region.contintent];
|
||||||
|
if (!continent.children) continent.children = [];
|
||||||
|
continent.children.push($option);
|
||||||
}
|
}
|
||||||
for (let value in setting.options) {
|
let fragment = document.createDocumentFragment(), key;
|
||||||
let label = setting.options[value], $option = CE("option", { value }, label);
|
for (key in continents) {
|
||||||
$control.appendChild($option);
|
let continent = continents[key];
|
||||||
|
if (!continent.children) continue;
|
||||||
|
fragment.appendChild(CE("optgroup", {
|
||||||
|
label: continent.label
|
||||||
|
}, ...continent.children));
|
||||||
}
|
}
|
||||||
return $control.disabled = Object.keys(STATES.serverRegions).length === 0, $control.value = selectedValue, $control;
|
return $control.appendChild(fragment), $control.disabled = Object.keys(STATES.serverRegions).length === 0, $control.value = selectedValue, $control;
|
||||||
}
|
}
|
||||||
renderSettingRow(settingTab, $tabContent, settingTabContent, setting) {
|
renderSettingRow(settingTab, $tabContent, settingTabContent, setting) {
|
||||||
if (typeof setting === "string") setting = {
|
if (typeof setting === "string") setting = {
|
||||||
@ -5034,21 +5068,22 @@ class StreamBadges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class XcloudInterceptor {
|
class XcloudInterceptor {
|
||||||
static SERVER_EMOJIS = {
|
static SERVER_EXTRA_INFO = {
|
||||||
AustraliaEast: "🇦🇺",
|
EastUS: ["🇺🇸", "america-north"],
|
||||||
AustraliaSouthEast: "🇦🇺",
|
EastUS2: ["🇺🇸", "america-north"],
|
||||||
BrazilSouth: "🇧🇷",
|
NorthCentralUs: ["🇺🇸", "america-north"],
|
||||||
EastUS: "🇺🇸",
|
SouthCentralUS: ["🇺🇸", "america-north"],
|
||||||
EastUS2: "🇺🇸",
|
WestUS: ["🇺🇸", "america-north"],
|
||||||
JapanEast: "🇯🇵",
|
WestUS2: ["🇺🇸", "america-north"],
|
||||||
KoreaCentral: "🇰🇷",
|
MexicoCentral: ["🇲🇽", "america-north"],
|
||||||
MexicoCentral: "🇲🇽",
|
BrazilSouth: ["🇧🇷", "america-south"],
|
||||||
NorthCentralUs: "🇺🇸",
|
JapanEast: ["🇯🇵", "asia"],
|
||||||
SouthCentralUS: "🇺🇸",
|
KoreaCentral: ["🇰🇷", "asia"],
|
||||||
UKSouth: "🇬🇧",
|
AustraliaEast: ["🇦🇺", "australia"],
|
||||||
WestEurope: "🇪🇺",
|
AustraliaSouthEast: ["🇦🇺", "australia"],
|
||||||
WestUS: "🇺🇸",
|
SwedenCentral: ["🇸🇪", "europe"],
|
||||||
WestUS2: "🇺🇸"
|
UKSouth: ["🇬🇧", "europe"],
|
||||||
|
WestEurope: ["🇪🇺", "europe"]
|
||||||
};
|
};
|
||||||
static async handleLogin(request, init) {
|
static async handleLogin(request, init) {
|
||||||
let bypassServer = getPref("server_bypass_restriction");
|
let bypassServer = getPref("server_bypass_restriction");
|
||||||
@ -5060,14 +5095,13 @@ class XcloudInterceptor {
|
|||||||
if (response.status !== 200) return BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_UNAVAILABLE), response;
|
if (response.status !== 200) return BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_UNAVAILABLE), response;
|
||||||
let obj = await response.clone().json();
|
let obj = await response.clone().json();
|
||||||
RemotePlayManager.getInstance().xcloudToken = obj.gsToken;
|
RemotePlayManager.getInstance().xcloudToken = obj.gsToken;
|
||||||
let serverRegex = /\/\/(\w+)\./, serverEmojis = XcloudInterceptor.SERVER_EMOJIS;
|
let serverRegex = /\/\/(\w+)\./, serverExtra = XcloudInterceptor.SERVER_EXTRA_INFO, region;
|
||||||
for (let region of obj.offeringSettings.regions) {
|
for (region of obj.offeringSettings.regions) {
|
||||||
let { name: regionName, name: shortName } = region;
|
let { name: regionName, name: shortName } = region;
|
||||||
if (region.isDefault) STATES.selectedRegion = Object.assign({}, region);
|
if (region.isDefault) STATES.selectedRegion = Object.assign({}, region);
|
||||||
let match = serverRegex.exec(region.baseUri);
|
let match = serverRegex.exec(region.baseUri);
|
||||||
if (match) {
|
if (match) if (shortName = match[1], serverExtra[regionName]) shortName = serverExtra[regionName][0] + " " + shortName, region.contintent = serverExtra[regionName][1];
|
||||||
if (shortName = match[1], serverEmojis[regionName]) shortName = serverEmojis[regionName] + " " + shortName;
|
else region.contintent = "other";
|
||||||
}
|
|
||||||
region.shortName = shortName.toUpperCase(), STATES.serverRegions[region.name] = Object.assign({}, region);
|
region.shortName = shortName.toUpperCase(), STATES.serverRegions[region.name] = Object.assign({}, region);
|
||||||
}
|
}
|
||||||
BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_READY);
|
BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_READY);
|
||||||
@ -5425,28 +5459,32 @@ class WebGL2Player {
|
|||||||
let gl = this.gl, program = this.program;
|
let gl = this.gl, program = this.program;
|
||||||
gl.uniform2f(gl.getUniformLocation(program, "iResolution"), this.$canvas.width, this.$canvas.height), gl.uniform1i(gl.getUniformLocation(program, "filterId"), this.options.filterId), gl.uniform1f(gl.getUniformLocation(program, "sharpenFactor"), this.options.sharpenFactor), gl.uniform1f(gl.getUniformLocation(program, "brightness"), this.options.brightness), gl.uniform1f(gl.getUniformLocation(program, "contrast"), this.options.contrast), gl.uniform1f(gl.getUniformLocation(program, "saturation"), this.options.saturation);
|
gl.uniform2f(gl.getUniformLocation(program, "iResolution"), this.$canvas.width, this.$canvas.height), gl.uniform1i(gl.getUniformLocation(program, "filterId"), this.options.filterId), gl.uniform1f(gl.getUniformLocation(program, "sharpenFactor"), this.options.sharpenFactor), gl.uniform1f(gl.getUniformLocation(program, "brightness"), this.options.brightness), gl.uniform1f(gl.getUniformLocation(program, "contrast"), this.options.contrast), gl.uniform1f(gl.getUniformLocation(program, "saturation"), this.options.saturation);
|
||||||
}
|
}
|
||||||
drawFrame(force = !1) {
|
forceDrawFrame() {
|
||||||
if (!force) {
|
|
||||||
if (this.targetFps === 0) return;
|
|
||||||
if (this.targetFps < 60) {
|
|
||||||
let currentTime = performance.now();
|
|
||||||
if (currentTime - this.lastFrameTime < this.frameInterval) return;
|
|
||||||
this.lastFrameTime = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let gl = this.gl;
|
let gl = this.gl;
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video), gl.drawArrays(gl.TRIANGLES, 0, 6);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video), gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
setupRendering() {
|
setupRendering() {
|
||||||
let animate;
|
let frameCallback;
|
||||||
if ("requestVideoFrameCallback" in HTMLVideoElement.prototype) {
|
if ("requestVideoFrameCallback" in HTMLVideoElement.prototype) {
|
||||||
let $video = this.$video;
|
let $video = this.$video;
|
||||||
animate = () => {
|
frameCallback = $video.requestVideoFrameCallback.bind($video);
|
||||||
if (!this.stopped) this.drawFrame(), this.animFrameId = $video.requestVideoFrameCallback(animate);
|
} else frameCallback = requestAnimationFrame;
|
||||||
}, this.animFrameId = $video.requestVideoFrameCallback(animate);
|
let animate = () => {
|
||||||
} else animate = () => {
|
if (this.stopped) return;
|
||||||
if (!this.stopped) this.drawFrame(), this.animFrameId = requestAnimationFrame(animate);
|
let draw = !0;
|
||||||
}, this.animFrameId = requestAnimationFrame(animate);
|
if (this.targetFps === 0) draw = !1;
|
||||||
|
else if (this.targetFps < 60) {
|
||||||
|
let currentTime = performance.now();
|
||||||
|
if (currentTime - this.lastFrameTime < this.frameInterval) draw = !1;
|
||||||
|
else this.lastFrameTime = currentTime;
|
||||||
|
}
|
||||||
|
if (draw) {
|
||||||
|
let gl = this.gl;
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video), gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
this.animFrameId = frameCallback(animate);
|
||||||
|
};
|
||||||
|
this.animFrameId = frameCallback(animate);
|
||||||
}
|
}
|
||||||
setupShaders() {
|
setupShaders() {
|
||||||
BxLogger.info(this.LOG_TAG, "Setting up", getPref("video_power_preference"));
|
BxLogger.info(this.LOG_TAG, "Setting up", getPref("video_power_preference"));
|
||||||
|
2
dist/better-xcloud.meta.js
vendored
2
dist/better-xcloud.meta.js
vendored
@ -1,5 +1,5 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.9.0
|
// @version 5.9.3
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
352
dist/better-xcloud.user.js
vendored
352
dist/better-xcloud.user.js
vendored
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Better xCloud
|
// @name Better xCloud
|
||||||
// @namespace https://github.com/redphx
|
// @namespace https://github.com/redphx
|
||||||
// @version 5.9.0
|
// @version 5.9.3
|
||||||
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
// @description Improve Xbox Cloud Gaming (xCloud) experience
|
||||||
// @author redphx
|
// @author redphx
|
||||||
// @license MIT
|
// @license MIT
|
||||||
@ -107,7 +107,7 @@ class UserAgent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var SCRIPT_VERSION = "5.9.0", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
var SCRIPT_VERSION = "5.9.3", SCRIPT_VARIANT = "full", AppInterface = window.AppInterface;
|
||||||
UserAgent.init();
|
UserAgent.init();
|
||||||
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.includes("smart-tv") || userAgent.includes("smarttv") || /\baft.*\b/.test(userAgent), isVr = window.navigator.userAgent.includes("VR") && window.navigator.userAgent.includes("OculusBrowser"), browserHasTouchSupport = "ontouchstart" in window || navigator.maxTouchPoints > 0, userAgentHasTouchSupport = !isTv && !isVr && browserHasTouchSupport, supportMkb = AppInterface || !userAgent.match(/(android|iphone|ipad)/), STATES = {
|
||||||
supportedRegion: !0,
|
supportedRegion: !0,
|
||||||
@ -323,6 +323,11 @@ var SUPPORTED_LANGUAGES = {
|
|||||||
"confirm-reload-stream": "Do you want to refresh the stream?",
|
"confirm-reload-stream": "Do you want to refresh the stream?",
|
||||||
connected: "Connected",
|
connected: "Connected",
|
||||||
"console-connect": "Connect",
|
"console-connect": "Connect",
|
||||||
|
"continent-asia": "Asia",
|
||||||
|
"continent-australia": "Australia",
|
||||||
|
"continent-europe": "Europe",
|
||||||
|
"continent-north-america": "North America",
|
||||||
|
"continent-south-america": "South America",
|
||||||
contrast: "Contrast",
|
contrast: "Contrast",
|
||||||
controller: "Controller",
|
controller: "Controller",
|
||||||
"controller-friendly-ui": "Controller-friendly UI",
|
"controller-friendly-ui": "Controller-friendly UI",
|
||||||
@ -426,7 +431,7 @@ var SUPPORTED_LANGUAGES = {
|
|||||||
e => `${e.version} 버전 사용가능`,
|
e => `${e.version} 버전 사용가능`,
|
||||||
e => `Dostępna jest nowa wersja ${e.version}`,
|
e => `Dostępna jest nowa wersja ${e.version}`,
|
||||||
e => `Versão ${e.version} disponível`,
|
e => `Versão ${e.version} disponível`,
|
||||||
,
|
e => `Версия ${e.version} доступна`,
|
||||||
e => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,
|
e => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,
|
||||||
e => `${e.version} sayılı yeni sürüm mevcut`,
|
e => `${e.version} sayılı yeni sürüm mevcut`,
|
||||||
e => `Доступна версія ${e.version}`,
|
e => `Доступна версія ${e.version}`,
|
||||||
@ -775,14 +780,16 @@ class SettingElement {
|
|||||||
}
|
}
|
||||||
static #renderNumberStepper(key, setting, value, onChange, options = {}) {
|
static #renderNumberStepper(key, setting, value, onChange, options = {}) {
|
||||||
options = options || {}, options.suffix = options.suffix || "", options.disabled = !!options.disabled, options.hideSlider = !!options.hideSlider;
|
options = options || {}, options.suffix = options.suffix || "", options.disabled = !!options.disabled, options.hideSlider = !!options.hideSlider;
|
||||||
let $text, $btnDec, $btnInc, $range = null, controlValue = value, MIN = options.reverse ? -setting.max : setting.min, MAX = options.reverse ? -setting.min : setting.max, STEPS = Math.max(setting.steps || 1, 1), renderTextValue = (value2) => {
|
let $text, $btnDec, $btnInc, $range = null, controlValue = value, MIN = options.reverse ? -setting.max : setting.min, MAX = options.reverse ? -setting.min : setting.max, STEPS = Math.max(setting.steps || 1, 1), intervalId, isHolding = !1, clearIntervalId = () => {
|
||||||
|
intervalId && clearInterval(intervalId), intervalId = null;
|
||||||
|
}, renderTextValue = (value2) => {
|
||||||
value2 = parseInt(value2);
|
value2 = parseInt(value2);
|
||||||
let textContent = null;
|
let textContent = null;
|
||||||
if (options.customTextValue) textContent = options.customTextValue(value2);
|
if (options.customTextValue) textContent = options.customTextValue(value2);
|
||||||
if (textContent === null) textContent = value2.toString() + options.suffix;
|
if (textContent === null) textContent = value2.toString() + options.suffix;
|
||||||
return textContent;
|
return textContent;
|
||||||
}, updateButtonsVisibility = () => {
|
}, updateButtonsVisibility = () => {
|
||||||
$btnDec.classList.toggle("bx-inactive", controlValue === MIN), $btnInc.classList.toggle("bx-inactive", controlValue === MAX);
|
if ($btnDec.classList.toggle("bx-inactive", controlValue === MIN), $btnInc.classList.toggle("bx-inactive", controlValue === MAX), controlValue === MIN || controlValue === MAX) clearIntervalId();
|
||||||
}, $wrapper = CE("div", { class: "bx-number-stepper", id: `bx_setting_${key}` }, $btnDec = CE("button", {
|
}, $wrapper = CE("div", { class: "bx-number-stepper", id: `bx_setting_${key}` }, $btnDec = CE("button", {
|
||||||
"data-type": "dec",
|
"data-type": "dec",
|
||||||
type: "button",
|
type: "button",
|
||||||
@ -796,7 +803,7 @@ class SettingElement {
|
|||||||
}, "+"));
|
}, "+"));
|
||||||
if (options.disabled) return $btnInc.disabled = !0, $btnInc.classList.add("bx-inactive"), $btnDec.disabled = !0, $btnDec.classList.add("bx-inactive"), $wrapper.disabled = !0, $wrapper;
|
if (options.disabled) return $btnInc.disabled = !0, $btnInc.classList.add("bx-inactive"), $btnDec.disabled = !0, $btnDec.classList.add("bx-inactive"), $wrapper.disabled = !0, $wrapper;
|
||||||
if ($range = CE("input", {
|
if ($range = CE("input", {
|
||||||
id: `bx_setting_${key}`,
|
id: `bx_inp_setting_${key}`,
|
||||||
type: "range",
|
type: "range",
|
||||||
min: MIN,
|
min: MIN,
|
||||||
max: MAX,
|
max: MAX,
|
||||||
@ -823,30 +830,29 @@ class SettingElement {
|
|||||||
$wrapper.appendChild($markers);
|
$wrapper.appendChild($markers);
|
||||||
}
|
}
|
||||||
updateButtonsVisibility();
|
updateButtonsVisibility();
|
||||||
let interval, isHolding = !1, onClick = (e) => {
|
let buttonPressed = (e, $btn) => {
|
||||||
if (isHolding) {
|
let value2 = parseInt(controlValue);
|
||||||
e.preventDefault(), isHolding = !1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let $btn = e.target, value2 = parseInt(controlValue);
|
|
||||||
if ($btn.dataset.type === "dec") value2 = Math.max(MIN, value2 - STEPS);
|
if ($btn.dataset.type === "dec") value2 = Math.max(MIN, value2 - STEPS);
|
||||||
else value2 = Math.min(MAX, value2 + STEPS);
|
else value2 = Math.min(MAX, value2 + STEPS);
|
||||||
controlValue = value2, updateButtonsVisibility(), $text.textContent = renderTextValue(value2), $range && ($range.value = value2.toString()), isHolding = !1, !e.ignoreOnChange && onChange && onChange(e, value2);
|
controlValue = value2, updateButtonsVisibility(), $text.textContent = renderTextValue(value2), $range && ($range.value = value2.toString()), onChange && onChange(e, value2);
|
||||||
}, onMouseDown = (e) => {
|
}, onClick = (e) => {
|
||||||
e.preventDefault(), isHolding = !0;
|
if (e.preventDefault(), isHolding) return;
|
||||||
let args = arguments;
|
let $btn = e.target.closest("button");
|
||||||
interval && clearInterval(interval), interval = window.setInterval(() => {
|
$btn && buttonPressed(e, $btn), clearIntervalId(), isHolding = !1;
|
||||||
e.target && BxEvent.dispatch(e.target, "click", {
|
}, onPointerDown = (e) => {
|
||||||
arguments: args
|
clearIntervalId();
|
||||||
});
|
let $btn = e.target.closest("button");
|
||||||
}, 200);
|
if (!$btn) return;
|
||||||
}, onMouseUp = (e) => {
|
isHolding = !0, e.preventDefault(), intervalId = window.setInterval((e2) => {
|
||||||
e.preventDefault(), interval && clearInterval(interval), isHolding = !1;
|
buttonPressed(e2, $btn);
|
||||||
|
}, 200), window.addEventListener("pointerup", onPointerUp, { once: !0 }), window.addEventListener("pointercancel", onPointerUp, { once: !0 });
|
||||||
|
}, onPointerUp = (e) => {
|
||||||
|
clearIntervalId(), isHolding = !1;
|
||||||
}, onContextMenu = (e) => e.preventDefault();
|
}, onContextMenu = (e) => e.preventDefault();
|
||||||
return $wrapper.setValue = (value2) => {
|
return $wrapper.setValue = (value2) => {
|
||||||
$text.textContent = renderTextValue(value2), $range.value = options.reverse ? -value2 : value2;
|
$text.textContent = renderTextValue(value2), $range.value = options.reverse ? -value2 : value2;
|
||||||
}, $btnDec.addEventListener("click", onClick), $btnDec.addEventListener("pointerdown", onMouseDown), $btnDec.addEventListener("pointerup", onMouseUp), $btnDec.addEventListener("contextmenu", onContextMenu), $btnInc.addEventListener("click", onClick), $btnInc.addEventListener("pointerdown", onMouseDown), $btnInc.addEventListener("pointerup", onMouseUp), $btnInc.addEventListener("contextmenu", onContextMenu), setNearby($wrapper, {
|
}, $wrapper.addEventListener("click", onClick), $wrapper.addEventListener("pointerdown", onPointerDown), $wrapper.addEventListener("contextmenu", onContextMenu), setNearby($wrapper, {
|
||||||
focus: $range || $btnInc
|
focus: options.hideSlider ? $btnInc : $range
|
||||||
}), $wrapper;
|
}), $wrapper;
|
||||||
}
|
}
|
||||||
static #METHOD_MAP = {
|
static #METHOD_MAP = {
|
||||||
@ -1416,7 +1422,7 @@ class GlobalSettingsStorage extends BaseSettingsStore {
|
|||||||
customTextValue(value) {
|
customTextValue(value) {
|
||||||
value = parseInt(value);
|
value = parseInt(value);
|
||||||
let text = +(1000 / value).toFixed(2) + " Hz";
|
let text = +(1000 / value).toFixed(2) + " Hz";
|
||||||
if (value === 4) text = `${t("default")} (${text})`;
|
if (value === 4) text = `${text} (${t("default")})`;
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1842,7 +1848,7 @@ class ScreenshotManager {
|
|||||||
if (!$player || !$player.isConnected) return;
|
if (!$player || !$player.isConnected) return;
|
||||||
$player.parentElement.addEventListener("animationend", this.onAnimationEnd, { once: !0 }), $player.parentElement.classList.add("bx-taking-screenshot");
|
$player.parentElement.addEventListener("animationend", this.onAnimationEnd, { once: !0 }), $player.parentElement.classList.add("bx-taking-screenshot");
|
||||||
let canvasContext = this.canvasContext;
|
let canvasContext = this.canvasContext;
|
||||||
if ($player instanceof HTMLCanvasElement) streamPlayer.getWebGL2Player().drawFrame(!0);
|
if ($player instanceof HTMLCanvasElement) streamPlayer.getWebGL2Player().forceDrawFrame();
|
||||||
if (canvasContext.drawImage($player, 0, 0, $canvas.width, $canvas.height), AppInterface) {
|
if (canvasContext.drawImage($player, 0, 0, $canvas.width, $canvas.height), AppInterface) {
|
||||||
let data = $canvas.toDataURL("image/png").split(";base64,")[1];
|
let data = $canvas.toDataURL("image/png").split(";base64,")[1];
|
||||||
AppInterface.saveScreenshot(currentStream.titleSlug, data), canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();
|
AppInterface.saveScreenshot(currentStream.titleSlug, data), canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();
|
||||||
@ -2656,7 +2662,7 @@ class NativeMkbHandler extends MkbHandler {
|
|||||||
}
|
}
|
||||||
class LocalDb {
|
class LocalDb {
|
||||||
static DB_NAME = "BetterXcloud";
|
static DB_NAME = "BetterXcloud";
|
||||||
static DB_VERSION = 1;
|
static DB_VERSION = 2;
|
||||||
db;
|
db;
|
||||||
open() {
|
open() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -2665,7 +2671,7 @@ class LocalDb {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let request = window.indexedDB.open(LocalDb.DB_NAME, LocalDb.DB_VERSION);
|
let request = window.indexedDB.open(LocalDb.DB_NAME, LocalDb.DB_VERSION);
|
||||||
request.onupgradeneeded = this.onUpgradeNeeded, request.onerror = (e) => {
|
request.onupgradeneeded = this.onUpgradeNeeded.bind(this), request.onerror = (e) => {
|
||||||
console.log(e), alert(e.target.error.message), reject && reject();
|
console.log(e), alert(e.target.error.message), reject && reject();
|
||||||
}, request.onsuccess = (e) => {
|
}, request.onsuccess = (e) => {
|
||||||
this.db = e.target.result, resolve();
|
this.db = e.target.result, resolve();
|
||||||
@ -2713,51 +2719,49 @@ class MkbPresetsDb extends LocalDb {
|
|||||||
super();
|
super();
|
||||||
BxLogger.info(this.LOG_TAG, "constructor()");
|
BxLogger.info(this.LOG_TAG, "constructor()");
|
||||||
}
|
}
|
||||||
|
createTable(db) {
|
||||||
|
db.createObjectStore(this.TABLE_PRESETS, {
|
||||||
|
keyPath: "id",
|
||||||
|
autoIncrement: !0
|
||||||
|
}).createIndex("name_idx", "name");
|
||||||
|
}
|
||||||
onUpgradeNeeded(e) {
|
onUpgradeNeeded(e) {
|
||||||
let db = e.target.result;
|
let db = e.target.result;
|
||||||
switch (e.oldVersion) {
|
if (db.objectStoreNames.contains("undefined")) db.deleteObjectStore("undefined");
|
||||||
case 0: {
|
if (!db.objectStoreNames.contains(this.TABLE_PRESETS)) this.createTable(db);
|
||||||
db.createObjectStore(this.TABLE_PRESETS, {
|
}
|
||||||
keyPath: "id",
|
async presetsTable() {
|
||||||
autoIncrement: !0
|
return await this.open(), await this.table(this.TABLE_PRESETS, "readwrite");
|
||||||
}).createIndex("name_idx", "name");
|
}
|
||||||
break;
|
async newPreset(name, data) {
|
||||||
}
|
let table = await this.presetsTable(), [, id2] = await this.add(table, { name, data });
|
||||||
|
return id2;
|
||||||
|
}
|
||||||
|
async updatePreset(preset) {
|
||||||
|
let table = await this.presetsTable(), [, id2] = await this.put(table, preset);
|
||||||
|
return id2;
|
||||||
|
}
|
||||||
|
async deletePreset(id2) {
|
||||||
|
let table = await this.presetsTable();
|
||||||
|
return await this.delete(table, id2), id2;
|
||||||
|
}
|
||||||
|
async getPreset(id2) {
|
||||||
|
let table = await this.presetsTable(), [, preset] = await this.get(table, id2);
|
||||||
|
return preset;
|
||||||
|
}
|
||||||
|
async getPresets() {
|
||||||
|
let table = await this.presetsTable(), [, count] = await this.count(table);
|
||||||
|
if (count > 0) {
|
||||||
|
let [, items] = await this.getAll(table), presets = {};
|
||||||
|
return items.forEach((item2) => presets[item2.id] = item2), presets;
|
||||||
}
|
}
|
||||||
}
|
let preset = {
|
||||||
presetsTable() {
|
name: t("default"),
|
||||||
return this.open().then(() => this.table(this.TABLE_PRESETS, "readwrite"));
|
data: MkbPreset.DEFAULT_PRESET
|
||||||
}
|
}, [, id2] = await this.add(table, preset);
|
||||||
newPreset(name, data) {
|
return preset.id = id2, setPref("mkb_default_preset_id", id2), {
|
||||||
return this.presetsTable().then((table) => this.add(table, { name, data })).then(([table, id2]) => new Promise((resolve) => resolve(id2)));
|
[id2]: preset
|
||||||
}
|
};
|
||||||
updatePreset(preset) {
|
|
||||||
return this.presetsTable().then((table) => this.put(table, preset)).then(([table, id2]) => new Promise((resolve) => resolve(id2)));
|
|
||||||
}
|
|
||||||
deletePreset(id2) {
|
|
||||||
return this.presetsTable().then((table) => this.delete(table, id2)).then(([table, id3]) => new Promise((resolve) => resolve(id3)));
|
|
||||||
}
|
|
||||||
getPreset(id2) {
|
|
||||||
return this.presetsTable().then((table) => this.get(table, id2)).then(([table, preset]) => new Promise((resolve) => resolve(preset)));
|
|
||||||
}
|
|
||||||
getPresets() {
|
|
||||||
return this.presetsTable().then((table) => this.count(table)).then(([table, count]) => {
|
|
||||||
if (count > 0) return new Promise((resolve) => {
|
|
||||||
this.getAll(table).then(([table2, items]) => {
|
|
||||||
let presets = {};
|
|
||||||
items.forEach((item2) => presets[item2.id] = item2), resolve(presets);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
let preset = {
|
|
||||||
name: t("default"),
|
|
||||||
data: MkbPreset.DEFAULT_PRESET
|
|
||||||
};
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.add(table, preset).then(([table2, id2]) => {
|
|
||||||
preset.id = id2, setPref("mkb_default_preset_id", id2), resolve({ [id2]: preset });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var PointerToMouseButton = {
|
var PointerToMouseButton = {
|
||||||
@ -3169,6 +3173,7 @@ class NavigationDialogManager {
|
|||||||
if (!width) return;
|
if (!width) return;
|
||||||
if ($select.multiple) $label = $parent.querySelector(".bx-select-value"), width += 20;
|
if ($select.multiple) $label = $parent.querySelector(".bx-select-value"), width += 20;
|
||||||
else $label = $parent.querySelector("div");
|
else $label = $parent.querySelector("div");
|
||||||
|
if ($select.querySelector("optgroup")) width -= 15;
|
||||||
$label.style.minWidth = width + "px", $parent.dataset.calculated = "true";
|
$label.style.minWidth = width + "px", $parent.dataset.calculated = "true";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3184,7 +3189,7 @@ class NavigationDialogManager {
|
|||||||
else if (keyCode === "ArrowLeft" || keyCode === "ArrowRight") {
|
else if (keyCode === "ArrowLeft" || keyCode === "ArrowRight") {
|
||||||
if (!($target instanceof HTMLInputElement && ($target.type === "text" || $target.type === "range"))) handled = !0, this.focusDirection(keyCode === "ArrowLeft" ? 4 : 2);
|
if (!($target instanceof HTMLInputElement && ($target.type === "text" || $target.type === "range"))) handled = !0, this.focusDirection(keyCode === "ArrowLeft" ? 4 : 2);
|
||||||
} else if (keyCode === "Enter" || keyCode === "NumpadEnter" || keyCode === "Space") {
|
} else if (keyCode === "Enter" || keyCode === "NumpadEnter" || keyCode === "Space") {
|
||||||
if (!($target instanceof HTMLInputElement && $target.type === "text")) handled = !0, $target.dispatchEvent(new MouseEvent("click"));
|
if (!($target instanceof HTMLInputElement && $target.type === "text")) handled = !0, $target.dispatchEvent(new MouseEvent("click", { bubbles: !0 }));
|
||||||
} else if (keyCode === "Escape") handled = !0, this.hide();
|
} else if (keyCode === "Escape") handled = !0, this.hide();
|
||||||
if (handled) event.preventDefault(), event.stopPropagation();
|
if (handled) event.preventDefault(), event.stopPropagation();
|
||||||
break;
|
break;
|
||||||
@ -3238,7 +3243,7 @@ class NavigationDialogManager {
|
|||||||
}
|
}
|
||||||
if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return;
|
if (this.gamepadLastStates[gamepad.index] = null, lastKeyPressed) return;
|
||||||
if (releasedButton === 0) {
|
if (releasedButton === 0) {
|
||||||
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent("click"));
|
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent("click", { bubbles: !0 }));
|
||||||
return;
|
return;
|
||||||
} else if (releasedButton === 1) {
|
} else if (releasedButton === 1) {
|
||||||
this.hide();
|
this.hide();
|
||||||
@ -3457,7 +3462,7 @@ class MkbRemapper {
|
|||||||
static instance;
|
static instance;
|
||||||
static getInstance = () => MkbRemapper.instance ?? (MkbRemapper.instance = new MkbRemapper);
|
static getInstance = () => MkbRemapper.instance ?? (MkbRemapper.instance = new MkbRemapper);
|
||||||
LOG_TAG = "MkbRemapper";
|
LOG_TAG = "MkbRemapper";
|
||||||
STATE = {
|
states = {
|
||||||
currentPresetId: 0,
|
currentPresetId: 0,
|
||||||
presets: {},
|
presets: {},
|
||||||
editingPresetData: null,
|
editingPresetData: null,
|
||||||
@ -3471,7 +3476,7 @@ class MkbRemapper {
|
|||||||
allMouseElements = {};
|
allMouseElements = {};
|
||||||
bindingDialog;
|
bindingDialog;
|
||||||
constructor() {
|
constructor() {
|
||||||
BxLogger.info(this.LOG_TAG, "constructor()"), this.STATE.currentPresetId = getPref("mkb_default_preset_id"), this.bindingDialog = new Dialog({
|
BxLogger.info(this.LOG_TAG, "constructor()"), this.states.currentPresetId = getPref("mkb_default_preset_id"), this.bindingDialog = new Dialog({
|
||||||
className: "bx-binding-dialog",
|
className: "bx-binding-dialog",
|
||||||
content: CE("div", {}, CE("p", {}, t("press-to-bind")), CE("i", {}, t("press-esc-to-cancel"))),
|
content: CE("div", {}, CE("p", {}, t("press-to-bind")), CE("i", {}, t("press-esc-to-cancel"))),
|
||||||
hideCloseButton: !0
|
hideCloseButton: !0
|
||||||
@ -3485,11 +3490,11 @@ class MkbRemapper {
|
|||||||
if ($elm.dataset.keyCode === key.code) return;
|
if ($elm.dataset.keyCode === key.code) return;
|
||||||
for (let $otherElm of this.allKeyElements)
|
for (let $otherElm of this.allKeyElements)
|
||||||
if ($otherElm.dataset.keyCode === key.code) this.unbindKey($otherElm);
|
if ($otherElm.dataset.keyCode === key.code) this.unbindKey($otherElm);
|
||||||
this.STATE.editingPresetData.mapping[buttonIndex][keySlot] = key.code, $elm.textContent = key.name, $elm.dataset.keyCode = key.code;
|
this.states.editingPresetData.mapping[buttonIndex][keySlot] = key.code, $elm.textContent = key.name, $elm.dataset.keyCode = key.code;
|
||||||
};
|
};
|
||||||
unbindKey = ($elm) => {
|
unbindKey = ($elm) => {
|
||||||
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot);
|
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot);
|
||||||
this.STATE.editingPresetData.mapping[buttonIndex][keySlot] = null, $elm.textContent = "", delete $elm.dataset.keyCode;
|
this.states.editingPresetData.mapping[buttonIndex][keySlot] = null, $elm.textContent = "", delete $elm.dataset.keyCode;
|
||||||
};
|
};
|
||||||
onWheel = (e) => {
|
onWheel = (e) => {
|
||||||
e.preventDefault(), this.clearEventListeners(), this.bindKey(this.$currentBindingKey, KeyHelper.getKeyFromEvent(e)), window.setTimeout(() => this.bindingDialog.hide(), 200);
|
e.preventDefault(), this.clearEventListeners(), this.bindKey(this.$currentBindingKey, KeyHelper.getKeyFromEvent(e)), window.setTimeout(() => this.bindingDialog.hide(), 200);
|
||||||
@ -3502,21 +3507,26 @@ class MkbRemapper {
|
|||||||
window.setTimeout(() => this.bindingDialog.hide(), 200);
|
window.setTimeout(() => this.bindingDialog.hide(), 200);
|
||||||
};
|
};
|
||||||
onBindingKey = (e) => {
|
onBindingKey = (e) => {
|
||||||
if (!this.STATE.isEditing || e.button !== 0) return;
|
if (!this.states.isEditing || e.button !== 0) return;
|
||||||
console.log(e), this.$currentBindingKey = e.target, window.addEventListener("keydown", this.onKeyDown), window.addEventListener("mousedown", this.onMouseDown), window.addEventListener("wheel", this.onWheel), this.bindingDialog.show({ title: this.$currentBindingKey.dataset.prompt });
|
console.log(e), this.$currentBindingKey = e.target, window.addEventListener("keydown", this.onKeyDown), window.addEventListener("mousedown", this.onMouseDown), window.addEventListener("wheel", this.onWheel), this.bindingDialog.show({ title: this.$currentBindingKey.dataset.prompt });
|
||||||
};
|
};
|
||||||
onContextMenu = (e) => {
|
onContextMenu = (e) => {
|
||||||
if (e.preventDefault(), !this.STATE.isEditing) return;
|
if (e.preventDefault(), !this.states.isEditing) return;
|
||||||
this.unbindKey(e.target);
|
this.unbindKey(e.target);
|
||||||
};
|
};
|
||||||
getPreset = (presetId) => {
|
getPreset = (presetId) => {
|
||||||
return this.STATE.presets[presetId];
|
return this.states.presets[presetId];
|
||||||
};
|
};
|
||||||
getCurrentPreset = () => {
|
getCurrentPreset = () => {
|
||||||
return this.getPreset(this.STATE.currentPresetId);
|
let preset = this.getPreset(this.states.currentPresetId);
|
||||||
|
if (!preset) {
|
||||||
|
let firstPresetId = parseInt(Object.keys(this.states.presets)[0]);
|
||||||
|
preset = this.states.presets[firstPresetId], this.states.currentPresetId = firstPresetId, setPref("mkb_default_preset_id", firstPresetId);
|
||||||
|
}
|
||||||
|
return preset;
|
||||||
};
|
};
|
||||||
switchPreset = (presetId) => {
|
switchPreset = (presetId) => {
|
||||||
this.STATE.currentPresetId = presetId;
|
this.states.currentPresetId = presetId;
|
||||||
let presetData = this.getCurrentPreset().data;
|
let presetData = this.getCurrentPreset().data;
|
||||||
for (let $elm of this.allKeyElements) {
|
for (let $elm of this.allKeyElements) {
|
||||||
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot), buttonKeys = presetData.mapping[buttonIndex];
|
let buttonIndex = parseInt($elm.dataset.buttonIndex), keySlot = parseInt($elm.dataset.keySlot), buttonKeys = presetData.mapping[buttonIndex];
|
||||||
@ -3529,35 +3539,33 @@ class MkbRemapper {
|
|||||||
if (typeof value === "undefined") value = MkbPreset.MOUSE_SETTINGS[key].default;
|
if (typeof value === "undefined") value = MkbPreset.MOUSE_SETTINGS[key].default;
|
||||||
"setValue" in $elm && $elm.setValue(value);
|
"setValue" in $elm && $elm.setValue(value);
|
||||||
}
|
}
|
||||||
let activated = getPref("mkb_default_preset_id") === this.STATE.currentPresetId;
|
let activated = getPref("mkb_default_preset_id") === this.states.currentPresetId;
|
||||||
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate");
|
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate");
|
||||||
};
|
};
|
||||||
refresh() {
|
async refresh() {
|
||||||
while (this.$presetsSelect.firstChild)
|
removeChildElements(this.$presetsSelect);
|
||||||
this.$presetsSelect.removeChild(this.$presetsSelect.firstChild);
|
let presets = await MkbPresetsDb.getInstance().getPresets();
|
||||||
MkbPresetsDb.getInstance().getPresets().then((presets) => {
|
this.states.presets = presets;
|
||||||
this.STATE.presets = presets;
|
let fragment = document.createDocumentFragment(), defaultPresetId;
|
||||||
let $fragment = document.createDocumentFragment(), defaultPresetId;
|
if (this.states.currentPresetId === 0) this.states.currentPresetId = parseInt(Object.keys(presets)[0]), defaultPresetId = this.states.currentPresetId, setPref("mkb_default_preset_id", defaultPresetId), EmulatedMkbHandler.getInstance().refreshPresetData();
|
||||||
if (this.STATE.currentPresetId === 0) this.STATE.currentPresetId = parseInt(Object.keys(presets)[0]), defaultPresetId = this.STATE.currentPresetId, setPref("mkb_default_preset_id", defaultPresetId), EmulatedMkbHandler.getInstance().refreshPresetData();
|
else defaultPresetId = getPref("mkb_default_preset_id");
|
||||||
else defaultPresetId = getPref("mkb_default_preset_id");
|
for (let id2 in presets) {
|
||||||
for (let id2 in presets) {
|
let name = presets[id2].name;
|
||||||
let name = presets[id2].name;
|
if (id2 === defaultPresetId) name = "🎮 " + name;
|
||||||
if (id2 === defaultPresetId) name = "🎮 " + name;
|
let $options = CE("option", { value: id2 }, name);
|
||||||
let $options = CE("option", { value: id2 }, name);
|
$options.selected = parseInt(id2) === this.states.currentPresetId, fragment.appendChild($options);
|
||||||
$options.selected = parseInt(id2) === this.STATE.currentPresetId, $fragment.appendChild($options);
|
}
|
||||||
}
|
this.$presetsSelect.appendChild(fragment);
|
||||||
this.$presetsSelect.appendChild($fragment);
|
let activated = defaultPresetId === this.states.currentPresetId;
|
||||||
let activated = defaultPresetId === this.STATE.currentPresetId;
|
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate"), !this.states.isEditing && this.switchPreset(this.states.currentPresetId);
|
||||||
this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate"), !this.STATE.isEditing && this.switchPreset(this.STATE.currentPresetId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
toggleEditing = (force) => {
|
toggleEditing = (force) => {
|
||||||
if (this.STATE.isEditing = typeof force !== "undefined" ? force : !this.STATE.isEditing, this.$wrapper.classList.toggle("bx-editing", this.STATE.isEditing), this.STATE.isEditing) this.STATE.editingPresetData = deepClone(this.getCurrentPreset().data);
|
if (this.states.isEditing = typeof force !== "undefined" ? force : !this.states.isEditing, this.$wrapper.classList.toggle("bx-editing", this.states.isEditing), this.states.isEditing) this.states.editingPresetData = deepClone(this.getCurrentPreset().data);
|
||||||
else this.STATE.editingPresetData = null;
|
else this.states.editingPresetData = null;
|
||||||
let childElements = this.$wrapper.querySelectorAll("select, button, input");
|
let childElements = this.$wrapper.querySelectorAll("select, button, input");
|
||||||
for (let $elm of Array.from(childElements)) {
|
for (let $elm of Array.from(childElements)) {
|
||||||
if ($elm.parentElement.parentElement.classList.contains("bx-mkb-action-buttons")) continue;
|
if ($elm.parentElement.parentElement.classList.contains("bx-mkb-action-buttons")) continue;
|
||||||
let disable = !this.STATE.isEditing;
|
let disable = !this.states.isEditing;
|
||||||
if ($elm.parentElement.classList.contains("bx-mkb-preset-tools")) disable = !disable;
|
if ($elm.parentElement.classList.contains("bx-mkb-preset-tools")) disable = !disable;
|
||||||
$elm.disabled = disable;
|
$elm.disabled = disable;
|
||||||
}
|
}
|
||||||
@ -3577,10 +3585,10 @@ class MkbRemapper {
|
|||||||
title: t("rename"),
|
title: t("rename"),
|
||||||
icon: BxIcon.CURSOR_TEXT,
|
icon: BxIcon.CURSOR_TEXT,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: async () => {
|
||||||
let preset = this.getCurrentPreset(), newName = promptNewName(preset.name);
|
let preset = this.getCurrentPreset(), newName = promptNewName(preset.name);
|
||||||
if (!newName || newName === preset.name) return;
|
if (!newName || newName === preset.name) return;
|
||||||
preset.name = newName, MkbPresetsDb.getInstance().updatePreset(preset).then((id2) => this.refresh());
|
preset.name = newName, await MkbPresetsDb.getInstance().updatePreset(preset), await this.refresh();
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
icon: BxIcon.NEW,
|
icon: BxIcon.NEW,
|
||||||
@ -3590,7 +3598,7 @@ class MkbRemapper {
|
|||||||
let newName = promptNewName("");
|
let newName = promptNewName("");
|
||||||
if (!newName) return;
|
if (!newName) return;
|
||||||
MkbPresetsDb.getInstance().newPreset(newName, MkbPreset.DEFAULT_PRESET).then((id2) => {
|
MkbPresetsDb.getInstance().newPreset(newName, MkbPreset.DEFAULT_PRESET).then((id2) => {
|
||||||
this.STATE.currentPresetId = id2, this.refresh();
|
this.states.currentPresetId = id2, this.refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
@ -3601,7 +3609,7 @@ class MkbRemapper {
|
|||||||
let preset = this.getCurrentPreset(), newName = promptNewName(`${preset.name} (2)`);
|
let preset = this.getCurrentPreset(), newName = promptNewName(`${preset.name} (2)`);
|
||||||
if (!newName) return;
|
if (!newName) return;
|
||||||
MkbPresetsDb.getInstance().newPreset(newName, preset.data).then((id2) => {
|
MkbPresetsDb.getInstance().newPreset(newName, preset.data).then((id2) => {
|
||||||
this.STATE.currentPresetId = id2, this.refresh();
|
this.states.currentPresetId = id2, this.refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
@ -3611,8 +3619,8 @@ class MkbRemapper {
|
|||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
if (!confirm(t("confirm-delete-preset"))) return;
|
if (!confirm(t("confirm-delete-preset"))) return;
|
||||||
MkbPresetsDb.getInstance().deletePreset(this.STATE.currentPresetId).then((id2) => {
|
MkbPresetsDb.getInstance().deletePreset(this.states.currentPresetId).then((id2) => {
|
||||||
this.STATE.currentPresetId = 0, this.refresh();
|
this.states.currentPresetId = 0, this.refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -3634,7 +3642,7 @@ class MkbRemapper {
|
|||||||
let $mouseSettings = document.createDocumentFragment();
|
let $mouseSettings = document.createDocumentFragment();
|
||||||
for (let key in MkbPreset.MOUSE_SETTINGS) {
|
for (let key in MkbPreset.MOUSE_SETTINGS) {
|
||||||
let setting = MkbPreset.MOUSE_SETTINGS[key], value = setting.default, $elm, onChange = (e, value2) => {
|
let setting = MkbPreset.MOUSE_SETTINGS[key], value = setting.default, $elm, onChange = (e, value2) => {
|
||||||
this.STATE.editingPresetData.mouse[key] = value2;
|
this.states.editingPresetData.mouse[key] = value2;
|
||||||
}, $row = CE("label", {
|
}, $row = CE("label", {
|
||||||
class: "bx-settings-row",
|
class: "bx-settings-row",
|
||||||
for: `bx_setting_${key}`
|
for: `bx_setting_${key}`
|
||||||
@ -3651,14 +3659,14 @@ class MkbRemapper {
|
|||||||
style: 1,
|
style: 1,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
setPref("mkb_default_preset_id", this.STATE.currentPresetId), EmulatedMkbHandler.getInstance().refreshPresetData(), this.refresh();
|
setPref("mkb_default_preset_id", this.states.currentPresetId), EmulatedMkbHandler.getInstance().refreshPresetData(), this.refresh();
|
||||||
}
|
}
|
||||||
})), CE("div", {}, createButton({
|
})), CE("div", {}, createButton({
|
||||||
label: t("cancel"),
|
label: t("cancel"),
|
||||||
style: 4,
|
style: 4,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
this.switchPreset(this.STATE.currentPresetId), this.toggleEditing(!1);
|
this.switchPreset(this.states.currentPresetId), this.toggleEditing(!1);
|
||||||
}
|
}
|
||||||
}), createButton({
|
}), createButton({
|
||||||
label: t("save"),
|
label: t("save"),
|
||||||
@ -3666,7 +3674,7 @@ class MkbRemapper {
|
|||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
let updatedPreset = deepClone(this.getCurrentPreset());
|
let updatedPreset = deepClone(this.getCurrentPreset());
|
||||||
updatedPreset.data = this.STATE.editingPresetData, MkbPresetsDb.getInstance().updatePreset(updatedPreset).then((id2) => {
|
updatedPreset.data = this.states.editingPresetData, MkbPresetsDb.getInstance().updatePreset(updatedPreset).then((id2) => {
|
||||||
if (id2 === getPref("mkb_default_preset_id")) EmulatedMkbHandler.getInstance().refreshPresetData();
|
if (id2 === getPref("mkb_default_preset_id")) EmulatedMkbHandler.getInstance().refreshPresetData();
|
||||||
this.toggleEditing(!1), this.refresh();
|
this.toggleEditing(!1), this.refresh();
|
||||||
});
|
});
|
||||||
@ -5242,26 +5250,52 @@ class SettingsNavigationDialog extends NavigationDialog {
|
|||||||
PatcherCache.clear(), this.$btnReload.classList.add("bx-danger"), this.$noteGlobalReload.classList.add("bx-gone"), this.$btnGlobalReload.classList.remove("bx-gone"), this.$btnGlobalReload.classList.add("bx-danger");
|
PatcherCache.clear(), this.$btnReload.classList.add("bx-danger"), this.$noteGlobalReload.classList.add("bx-gone"), this.$btnGlobalReload.classList.remove("bx-gone"), this.$btnGlobalReload.classList.add("bx-danger");
|
||||||
}
|
}
|
||||||
renderServerSetting(setting) {
|
renderServerSetting(setting) {
|
||||||
let selectedValue, $control = CE("select", {
|
let selectedValue = getPref("server_region"), continents = {
|
||||||
|
"america-north": {
|
||||||
|
label: t("continent-north-america")
|
||||||
|
},
|
||||||
|
"america-south": {
|
||||||
|
label: t("continent-south-america")
|
||||||
|
},
|
||||||
|
asia: {
|
||||||
|
label: t("continent-asia")
|
||||||
|
},
|
||||||
|
australia: {
|
||||||
|
label: t("continent-australia")
|
||||||
|
},
|
||||||
|
europe: {
|
||||||
|
label: t("continent-europe")
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
label: t("other")
|
||||||
|
}
|
||||||
|
}, $control = CE("select", {
|
||||||
id: `bx_setting_${setting.pref}`,
|
id: `bx_setting_${setting.pref}`,
|
||||||
title: setting.label,
|
title: setting.label,
|
||||||
tabindex: 0
|
tabindex: 0
|
||||||
});
|
});
|
||||||
$control.name = $control.id, $control.addEventListener("input", (e) => {
|
$control.name = $control.id, $control.addEventListener("input", (e) => {
|
||||||
setPref(setting.pref, e.target.value), this.onGlobalSettingChanged(e);
|
setPref(setting.pref, e.target.value), this.onGlobalSettingChanged(e);
|
||||||
}), selectedValue = getPref("server_region"), setting.options = {};
|
}), setting.options = {};
|
||||||
for (let regionName in STATES.serverRegions) {
|
for (let regionName in STATES.serverRegions) {
|
||||||
let region = STATES.serverRegions[regionName], value = regionName, label = `${region.shortName} - ${regionName}`;
|
let region = STATES.serverRegions[regionName], value = regionName, label = `${region.shortName} - ${regionName}`;
|
||||||
if (region.isDefault) {
|
if (region.isDefault) {
|
||||||
if (label += ` (${t("default")})`, value = "default", selectedValue === regionName) selectedValue = "default";
|
if (label += ` (${t("default")})`, value = "default", selectedValue === regionName) selectedValue = "default";
|
||||||
}
|
}
|
||||||
setting.options[value] = label;
|
setting.options[value] = label;
|
||||||
|
let $option = CE("option", { value }, label), continent = continents[region.contintent];
|
||||||
|
if (!continent.children) continent.children = [];
|
||||||
|
continent.children.push($option);
|
||||||
}
|
}
|
||||||
for (let value in setting.options) {
|
let fragment = document.createDocumentFragment(), key;
|
||||||
let label = setting.options[value], $option = CE("option", { value }, label);
|
for (key in continents) {
|
||||||
$control.appendChild($option);
|
let continent = continents[key];
|
||||||
|
if (!continent.children) continue;
|
||||||
|
fragment.appendChild(CE("optgroup", {
|
||||||
|
label: continent.label
|
||||||
|
}, ...continent.children));
|
||||||
}
|
}
|
||||||
return $control.disabled = Object.keys(STATES.serverRegions).length === 0, $control.value = selectedValue, $control;
|
return $control.appendChild(fragment), $control.disabled = Object.keys(STATES.serverRegions).length === 0, $control.value = selectedValue, $control;
|
||||||
}
|
}
|
||||||
renderSettingRow(settingTab, $tabContent, settingTabContent, setting) {
|
renderSettingRow(settingTab, $tabContent, settingTabContent, setting) {
|
||||||
if (typeof setting === "string") setting = {
|
if (typeof setting === "string") setting = {
|
||||||
@ -6110,7 +6144,7 @@ class XhomeInterceptor {
|
|||||||
["ipV6Address", "ipV6Port"]
|
["ipV6Address", "ipV6Port"]
|
||||||
];
|
];
|
||||||
XhomeInterceptor.consoleAddrs = {};
|
XhomeInterceptor.consoleAddrs = {};
|
||||||
for (let pair in pairs) {
|
for (let pair of pairs) {
|
||||||
let [keyAddr, keyPort] = pair;
|
let [keyAddr, keyPort] = pair;
|
||||||
if (serverDetails[keyAddr]) {
|
if (serverDetails[keyAddr]) {
|
||||||
let port = serverDetails[keyPort], ports = new Set;
|
let port = serverDetails[keyPort], ports = new Set;
|
||||||
@ -6611,21 +6645,22 @@ class StreamBadges {
|
|||||||
static setupEvents() {}
|
static setupEvents() {}
|
||||||
}
|
}
|
||||||
class XcloudInterceptor {
|
class XcloudInterceptor {
|
||||||
static SERVER_EMOJIS = {
|
static SERVER_EXTRA_INFO = {
|
||||||
AustraliaEast: "🇦🇺",
|
EastUS: ["🇺🇸", "america-north"],
|
||||||
AustraliaSouthEast: "🇦🇺",
|
EastUS2: ["🇺🇸", "america-north"],
|
||||||
BrazilSouth: "🇧🇷",
|
NorthCentralUs: ["🇺🇸", "america-north"],
|
||||||
EastUS: "🇺🇸",
|
SouthCentralUS: ["🇺🇸", "america-north"],
|
||||||
EastUS2: "🇺🇸",
|
WestUS: ["🇺🇸", "america-north"],
|
||||||
JapanEast: "🇯🇵",
|
WestUS2: ["🇺🇸", "america-north"],
|
||||||
KoreaCentral: "🇰🇷",
|
MexicoCentral: ["🇲🇽", "america-north"],
|
||||||
MexicoCentral: "🇲🇽",
|
BrazilSouth: ["🇧🇷", "america-south"],
|
||||||
NorthCentralUs: "🇺🇸",
|
JapanEast: ["🇯🇵", "asia"],
|
||||||
SouthCentralUS: "🇺🇸",
|
KoreaCentral: ["🇰🇷", "asia"],
|
||||||
UKSouth: "🇬🇧",
|
AustraliaEast: ["🇦🇺", "australia"],
|
||||||
WestEurope: "🇪🇺",
|
AustraliaSouthEast: ["🇦🇺", "australia"],
|
||||||
WestUS: "🇺🇸",
|
SwedenCentral: ["🇸🇪", "europe"],
|
||||||
WestUS2: "🇺🇸"
|
UKSouth: ["🇬🇧", "europe"],
|
||||||
|
WestEurope: ["🇪🇺", "europe"]
|
||||||
};
|
};
|
||||||
static async handleLogin(request, init) {
|
static async handleLogin(request, init) {
|
||||||
let bypassServer = getPref("server_bypass_restriction");
|
let bypassServer = getPref("server_bypass_restriction");
|
||||||
@ -6637,14 +6672,13 @@ class XcloudInterceptor {
|
|||||||
if (response.status !== 200) return BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_UNAVAILABLE), response;
|
if (response.status !== 200) return BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_UNAVAILABLE), response;
|
||||||
let obj = await response.clone().json();
|
let obj = await response.clone().json();
|
||||||
RemotePlayManager.getInstance().xcloudToken = obj.gsToken;
|
RemotePlayManager.getInstance().xcloudToken = obj.gsToken;
|
||||||
let serverRegex = /\/\/(\w+)\./, serverEmojis = XcloudInterceptor.SERVER_EMOJIS;
|
let serverRegex = /\/\/(\w+)\./, serverExtra = XcloudInterceptor.SERVER_EXTRA_INFO, region;
|
||||||
for (let region of obj.offeringSettings.regions) {
|
for (region of obj.offeringSettings.regions) {
|
||||||
let { name: regionName, name: shortName } = region;
|
let { name: regionName, name: shortName } = region;
|
||||||
if (region.isDefault) STATES.selectedRegion = Object.assign({}, region);
|
if (region.isDefault) STATES.selectedRegion = Object.assign({}, region);
|
||||||
let match = serverRegex.exec(region.baseUri);
|
let match = serverRegex.exec(region.baseUri);
|
||||||
if (match) {
|
if (match) if (shortName = match[1], serverExtra[regionName]) shortName = serverExtra[regionName][0] + " " + shortName, region.contintent = serverExtra[regionName][1];
|
||||||
if (shortName = match[1], serverEmojis[regionName]) shortName = serverEmojis[regionName] + " " + shortName;
|
else region.contintent = "other";
|
||||||
}
|
|
||||||
region.shortName = shortName.toUpperCase(), STATES.serverRegions[region.name] = Object.assign({}, region);
|
region.shortName = shortName.toUpperCase(), STATES.serverRegions[region.name] = Object.assign({}, region);
|
||||||
}
|
}
|
||||||
BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_READY);
|
BxEvent.dispatch(window, BxEvent.XCLOUD_SERVERS_READY);
|
||||||
@ -7041,28 +7075,32 @@ class WebGL2Player {
|
|||||||
let gl = this.gl, program = this.program;
|
let gl = this.gl, program = this.program;
|
||||||
gl.uniform2f(gl.getUniformLocation(program, "iResolution"), this.$canvas.width, this.$canvas.height), gl.uniform1i(gl.getUniformLocation(program, "filterId"), this.options.filterId), gl.uniform1f(gl.getUniformLocation(program, "sharpenFactor"), this.options.sharpenFactor), gl.uniform1f(gl.getUniformLocation(program, "brightness"), this.options.brightness), gl.uniform1f(gl.getUniformLocation(program, "contrast"), this.options.contrast), gl.uniform1f(gl.getUniformLocation(program, "saturation"), this.options.saturation);
|
gl.uniform2f(gl.getUniformLocation(program, "iResolution"), this.$canvas.width, this.$canvas.height), gl.uniform1i(gl.getUniformLocation(program, "filterId"), this.options.filterId), gl.uniform1f(gl.getUniformLocation(program, "sharpenFactor"), this.options.sharpenFactor), gl.uniform1f(gl.getUniformLocation(program, "brightness"), this.options.brightness), gl.uniform1f(gl.getUniformLocation(program, "contrast"), this.options.contrast), gl.uniform1f(gl.getUniformLocation(program, "saturation"), this.options.saturation);
|
||||||
}
|
}
|
||||||
drawFrame(force = !1) {
|
forceDrawFrame() {
|
||||||
if (!force) {
|
|
||||||
if (this.targetFps === 0) return;
|
|
||||||
if (this.targetFps < 60) {
|
|
||||||
let currentTime = performance.now();
|
|
||||||
if (currentTime - this.lastFrameTime < this.frameInterval) return;
|
|
||||||
this.lastFrameTime = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let gl = this.gl;
|
let gl = this.gl;
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video), gl.drawArrays(gl.TRIANGLES, 0, 6);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video), gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
setupRendering() {
|
setupRendering() {
|
||||||
let animate;
|
let frameCallback;
|
||||||
if ("requestVideoFrameCallback" in HTMLVideoElement.prototype) {
|
if ("requestVideoFrameCallback" in HTMLVideoElement.prototype) {
|
||||||
let $video = this.$video;
|
let $video = this.$video;
|
||||||
animate = () => {
|
frameCallback = $video.requestVideoFrameCallback.bind($video);
|
||||||
if (!this.stopped) this.drawFrame(), this.animFrameId = $video.requestVideoFrameCallback(animate);
|
} else frameCallback = requestAnimationFrame;
|
||||||
}, this.animFrameId = $video.requestVideoFrameCallback(animate);
|
let animate = () => {
|
||||||
} else animate = () => {
|
if (this.stopped) return;
|
||||||
if (!this.stopped) this.drawFrame(), this.animFrameId = requestAnimationFrame(animate);
|
let draw = !0;
|
||||||
}, this.animFrameId = requestAnimationFrame(animate);
|
if (this.targetFps === 0) draw = !1;
|
||||||
|
else if (this.targetFps < 60) {
|
||||||
|
let currentTime = performance.now();
|
||||||
|
if (currentTime - this.lastFrameTime < this.frameInterval) draw = !1;
|
||||||
|
else this.lastFrameTime = currentTime;
|
||||||
|
}
|
||||||
|
if (draw) {
|
||||||
|
let gl = this.gl;
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video), gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
this.animFrameId = frameCallback(animate);
|
||||||
|
};
|
||||||
|
this.animFrameId = frameCallback(animate);
|
||||||
}
|
}
|
||||||
setupShaders() {
|
setupShaders() {
|
||||||
BxLogger.info(this.LOG_TAG, "Setting up", getPref("video_power_preference"));
|
BxLogger.info(this.LOG_TAG, "Setting up", getPref("video_power_preference"));
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
"build": "build.ts"
|
"build": "build.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.1.11",
|
"@types/bun": "^1.1.12",
|
||||||
"@types/node": "^22.7.8",
|
"@types/node": "^22.7.9",
|
||||||
"@types/stylus": "^0.48.43",
|
"@types/stylus": "^0.48.43",
|
||||||
"eslint": "^9.13.0",
|
"eslint": "^9.13.0",
|
||||||
"eslint-plugin-compat": "^6.0.1",
|
"eslint-plugin-compat": "^6.0.1",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CE, createButton, ButtonStyle } from "@utils/html";
|
import { CE, createButton, ButtonStyle, removeChildElements } from "@utils/html";
|
||||||
import { t } from "@utils/translation";
|
import { t } from "@utils/translation";
|
||||||
import { Dialog } from "@modules/dialog";
|
import { Dialog } from "@modules/dialog";
|
||||||
import { KeyHelper } from "./key-helper";
|
import { KeyHelper } from "./key-helper";
|
||||||
@ -61,12 +61,10 @@ export class MkbRemapper {
|
|||||||
public static getInstance = () => MkbRemapper.instance ?? (MkbRemapper.instance = new MkbRemapper());
|
public static getInstance = () => MkbRemapper.instance ?? (MkbRemapper.instance = new MkbRemapper());
|
||||||
private readonly LOG_TAG = 'MkbRemapper';
|
private readonly LOG_TAG = 'MkbRemapper';
|
||||||
|
|
||||||
private STATE: MkbRemapperStates = {
|
private states: MkbRemapperStates = {
|
||||||
currentPresetId: 0,
|
currentPresetId: 0,
|
||||||
presets: {},
|
presets: {},
|
||||||
|
|
||||||
editingPresetData: null,
|
editingPresetData: null,
|
||||||
|
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,7 +81,7 @@ export class MkbRemapper {
|
|||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
BxLogger.info(this.LOG_TAG, 'constructor()');
|
BxLogger.info(this.LOG_TAG, 'constructor()');
|
||||||
this.STATE.currentPresetId = getPref(PrefKey.MKB_DEFAULT_PRESET_ID);
|
this.states.currentPresetId = getPref(PrefKey.MKB_DEFAULT_PRESET_ID);
|
||||||
|
|
||||||
this.bindingDialog = new Dialog({
|
this.bindingDialog = new Dialog({
|
||||||
className: 'bx-binding-dialog',
|
className: 'bx-binding-dialog',
|
||||||
@ -117,7 +115,7 @@ export class MkbRemapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.STATE.editingPresetData!.mapping[buttonIndex][keySlot] = key.code;
|
this.states.editingPresetData!.mapping[buttonIndex][keySlot] = key.code;
|
||||||
$elm.textContent = key.name;
|
$elm.textContent = key.name;
|
||||||
$elm.dataset.keyCode = key.code;
|
$elm.dataset.keyCode = key.code;
|
||||||
}
|
}
|
||||||
@ -127,7 +125,7 @@ export class MkbRemapper {
|
|||||||
const keySlot = parseInt($elm.dataset.keySlot!);
|
const keySlot = parseInt($elm.dataset.keySlot!);
|
||||||
|
|
||||||
// Remove key from preset
|
// Remove key from preset
|
||||||
this.STATE.editingPresetData!.mapping[buttonIndex][keySlot] = null;
|
this.states.editingPresetData!.mapping[buttonIndex][keySlot] = null;
|
||||||
$elm.textContent = '';
|
$elm.textContent = '';
|
||||||
delete $elm.dataset.keyCode;
|
delete $elm.dataset.keyCode;
|
||||||
}
|
}
|
||||||
@ -161,7 +159,7 @@ export class MkbRemapper {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private onBindingKey = (e: MouseEvent) => {
|
private onBindingKey = (e: MouseEvent) => {
|
||||||
if (!this.STATE.isEditing || e.button !== 0) {
|
if (!this.states.isEditing || e.button !== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +176,7 @@ export class MkbRemapper {
|
|||||||
|
|
||||||
private onContextMenu = (e: Event) => {
|
private onContextMenu = (e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!this.STATE.isEditing) {
|
if (!this.states.isEditing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,15 +184,24 @@ export class MkbRemapper {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private getPreset = (presetId: number) => {
|
private getPreset = (presetId: number) => {
|
||||||
return this.STATE.presets[presetId];
|
return this.states.presets[presetId];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCurrentPreset = () => {
|
private getCurrentPreset = () => {
|
||||||
return this.getPreset(this.STATE.currentPresetId);
|
let preset = this.getPreset(this.states.currentPresetId);
|
||||||
|
if (!preset) {
|
||||||
|
// Get the first preset in the list
|
||||||
|
const firstPresetId = parseInt(Object.keys(this.states.presets)[0]);
|
||||||
|
preset = this.states.presets[firstPresetId];
|
||||||
|
this.states.currentPresetId = firstPresetId;
|
||||||
|
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, firstPresetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return preset;
|
||||||
}
|
}
|
||||||
|
|
||||||
private switchPreset = (presetId: number) => {
|
private switchPreset = (presetId: number) => {
|
||||||
this.STATE.currentPresetId = presetId;
|
this.states.currentPresetId = presetId;
|
||||||
const presetData = this.getCurrentPreset().data;
|
const presetData = this.getCurrentPreset().data;
|
||||||
|
|
||||||
for (const $elm of this.allKeyElements) {
|
for (const $elm of this.allKeyElements) {
|
||||||
@ -223,64 +230,62 @@ export class MkbRemapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update state of Activate button
|
// Update state of Activate button
|
||||||
const activated = getPref(PrefKey.MKB_DEFAULT_PRESET_ID) === this.STATE.currentPresetId;
|
const activated = getPref(PrefKey.MKB_DEFAULT_PRESET_ID) === this.states.currentPresetId;
|
||||||
this.$activateButton.disabled = activated;
|
this.$activateButton.disabled = activated;
|
||||||
this.$activateButton.querySelector('span')!.textContent = activated ? t('activated') : t('activate');
|
this.$activateButton.querySelector('span')!.textContent = activated ? t('activated') : t('activate');
|
||||||
}
|
}
|
||||||
|
|
||||||
private refresh() {
|
private async refresh() {
|
||||||
// Clear presets select
|
// Clear presets select
|
||||||
while (this.$presetsSelect.firstChild) {
|
removeChildElements(this.$presetsSelect);
|
||||||
this.$presetsSelect.removeChild(this.$presetsSelect.firstChild);
|
|
||||||
|
const presets = await MkbPresetsDb.getInstance().getPresets();
|
||||||
|
|
||||||
|
this.states.presets = presets;
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
|
||||||
|
let defaultPresetId;
|
||||||
|
if (this.states.currentPresetId === 0) {
|
||||||
|
this.states.currentPresetId = parseInt(Object.keys(presets)[0]);
|
||||||
|
|
||||||
|
defaultPresetId = this.states.currentPresetId;
|
||||||
|
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, defaultPresetId);
|
||||||
|
EmulatedMkbHandler.getInstance().refreshPresetData();
|
||||||
|
} else {
|
||||||
|
defaultPresetId = getPref(PrefKey.MKB_DEFAULT_PRESET_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
MkbPresetsDb.getInstance().getPresets().then(presets => {
|
for (let id in presets) {
|
||||||
this.STATE.presets = presets;
|
const preset = presets[id];
|
||||||
const $fragment = document.createDocumentFragment();
|
let name = preset.name;
|
||||||
|
if (id === defaultPresetId) {
|
||||||
let defaultPresetId;
|
name = `🎮 ` + name;
|
||||||
if (this.STATE.currentPresetId === 0) {
|
|
||||||
this.STATE.currentPresetId = parseInt(Object.keys(presets)[0]);
|
|
||||||
|
|
||||||
defaultPresetId = this.STATE.currentPresetId;
|
|
||||||
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, defaultPresetId);
|
|
||||||
EmulatedMkbHandler.getInstance().refreshPresetData();
|
|
||||||
} else {
|
|
||||||
defaultPresetId = getPref(PrefKey.MKB_DEFAULT_PRESET_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let id in presets) {
|
const $options = CE<HTMLOptionElement>('option', {value: id}, name);
|
||||||
const preset = presets[id];
|
$options.selected = parseInt(id) === this.states.currentPresetId;
|
||||||
let name = preset.name;
|
|
||||||
if (id === defaultPresetId) {
|
|
||||||
name = `🎮 ` + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $options = CE<HTMLOptionElement>('option', {value: id}, name);
|
fragment.appendChild($options);
|
||||||
$options.selected = parseInt(id) === this.STATE.currentPresetId;
|
};
|
||||||
|
|
||||||
$fragment.appendChild($options);
|
this.$presetsSelect.appendChild(fragment);
|
||||||
};
|
|
||||||
|
|
||||||
this.$presetsSelect.appendChild($fragment);
|
// Update state of Activate button
|
||||||
|
const activated = defaultPresetId === this.states.currentPresetId;
|
||||||
|
this.$activateButton.disabled = activated;
|
||||||
|
this.$activateButton.querySelector('span')!.textContent = activated ? t('activated') : t('activate');
|
||||||
|
|
||||||
// Update state of Activate button
|
!this.states.isEditing && this.switchPreset(this.states.currentPresetId);
|
||||||
const activated = defaultPresetId === this.STATE.currentPresetId;
|
|
||||||
this.$activateButton.disabled = activated;
|
|
||||||
this.$activateButton.querySelector('span')!.textContent = activated ? t('activated') : t('activate');
|
|
||||||
|
|
||||||
!this.STATE.isEditing && this.switchPreset(this.STATE.currentPresetId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private toggleEditing = (force?: boolean) => {
|
private toggleEditing = (force?: boolean) => {
|
||||||
this.STATE.isEditing = typeof force !== 'undefined' ? force : !this.STATE.isEditing;
|
this.states.isEditing = typeof force !== 'undefined' ? force : !this.states.isEditing;
|
||||||
this.$wrapper.classList.toggle('bx-editing', this.STATE.isEditing);
|
this.$wrapper.classList.toggle('bx-editing', this.states.isEditing);
|
||||||
|
|
||||||
if (this.STATE.isEditing) {
|
if (this.states.isEditing) {
|
||||||
this.STATE.editingPresetData = deepClone(this.getCurrentPreset().data);
|
this.states.editingPresetData = deepClone(this.getCurrentPreset().data);
|
||||||
} else {
|
} else {
|
||||||
this.STATE.editingPresetData = null;
|
this.states.editingPresetData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -290,7 +295,7 @@ export class MkbRemapper {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let disable = !this.STATE.isEditing;
|
let disable = !this.states.isEditing;
|
||||||
|
|
||||||
if ($elm.parentElement!.classList.contains('bx-mkb-preset-tools')) {
|
if ($elm.parentElement!.classList.contains('bx-mkb-preset-tools')) {
|
||||||
disable = !disable;
|
disable = !disable;
|
||||||
@ -328,7 +333,7 @@ export class MkbRemapper {
|
|||||||
title: t('rename'),
|
title: t('rename'),
|
||||||
icon: BxIcon.CURSOR_TEXT,
|
icon: BxIcon.CURSOR_TEXT,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: e => {
|
onClick: async () => {
|
||||||
const preset = this.getCurrentPreset();
|
const preset = this.getCurrentPreset();
|
||||||
|
|
||||||
let newName = promptNewName(preset.name);
|
let newName = promptNewName(preset.name);
|
||||||
@ -338,7 +343,9 @@ export class MkbRemapper {
|
|||||||
|
|
||||||
// Update preset with new name
|
// Update preset with new name
|
||||||
preset.name = newName;
|
preset.name = newName;
|
||||||
MkbPresetsDb.getInstance().updatePreset(preset).then(id => this.refresh());
|
|
||||||
|
await MkbPresetsDb.getInstance().updatePreset(preset);
|
||||||
|
await this.refresh();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -355,7 +362,7 @@ export class MkbRemapper {
|
|||||||
|
|
||||||
// Create new preset selected name
|
// Create new preset selected name
|
||||||
MkbPresetsDb.getInstance().newPreset(newName, MkbPreset.DEFAULT_PRESET).then(id => {
|
MkbPresetsDb.getInstance().newPreset(newName, MkbPreset.DEFAULT_PRESET).then(id => {
|
||||||
this.STATE.currentPresetId = id;
|
this.states.currentPresetId = id;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -376,7 +383,7 @@ export class MkbRemapper {
|
|||||||
|
|
||||||
// Create new preset selected name
|
// Create new preset selected name
|
||||||
MkbPresetsDb.getInstance().newPreset(newName, preset.data).then(id => {
|
MkbPresetsDb.getInstance().newPreset(newName, preset.data).then(id => {
|
||||||
this.STATE.currentPresetId = id;
|
this.states.currentPresetId = id;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -393,8 +400,8 @@ export class MkbRemapper {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MkbPresetsDb.getInstance().deletePreset(this.STATE.currentPresetId).then(id => {
|
MkbPresetsDb.getInstance().deletePreset(this.states.currentPresetId).then(id => {
|
||||||
this.STATE.currentPresetId = 0;
|
this.states.currentPresetId = 0;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -448,7 +455,7 @@ export class MkbRemapper {
|
|||||||
|
|
||||||
let $elm;
|
let $elm;
|
||||||
const onChange = (e: Event, value: any) => {
|
const onChange = (e: Event, value: any) => {
|
||||||
(this.STATE.editingPresetData!.mouse as any)[key] = value;
|
(this.states.editingPresetData!.mouse as any)[key] = value;
|
||||||
};
|
};
|
||||||
const $row = CE('label', {
|
const $row = CE('label', {
|
||||||
class: 'bx-settings-row',
|
class: 'bx-settings-row',
|
||||||
@ -481,7 +488,7 @@ export class MkbRemapper {
|
|||||||
style: ButtonStyle.PRIMARY,
|
style: ButtonStyle.PRIMARY,
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, this.STATE.currentPresetId);
|
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, this.states.currentPresetId);
|
||||||
EmulatedMkbHandler.getInstance().refreshPresetData();
|
EmulatedMkbHandler.getInstance().refreshPresetData();
|
||||||
|
|
||||||
this.refresh();
|
this.refresh();
|
||||||
@ -497,7 +504,7 @@ export class MkbRemapper {
|
|||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
// Restore preset
|
// Restore preset
|
||||||
this.switchPreset(this.STATE.currentPresetId);
|
this.switchPreset(this.states.currentPresetId);
|
||||||
this.toggleEditing(false);
|
this.toggleEditing(false);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -509,7 +516,7 @@ export class MkbRemapper {
|
|||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
const updatedPreset = deepClone(this.getCurrentPreset());
|
const updatedPreset = deepClone(this.getCurrentPreset());
|
||||||
updatedPreset.data = this.STATE.editingPresetData as MkbPresetData;
|
updatedPreset.data = this.states.editingPresetData as MkbPresetData;
|
||||||
|
|
||||||
MkbPresetsDb.getInstance().updatePreset(updatedPreset).then(id => {
|
MkbPresetsDb.getInstance().updatePreset(updatedPreset).then(id => {
|
||||||
// If this is the default preset => refresh preset data
|
// If this is the default preset => refresh preset data
|
||||||
|
@ -94,52 +94,52 @@ export class WebGL2Player {
|
|||||||
gl.uniform1f(gl.getUniformLocation(program, 'saturation'), this.options.saturation);
|
gl.uniform1f(gl.getUniformLocation(program, 'saturation'), this.options.saturation);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawFrame(force=false) {
|
forceDrawFrame() {
|
||||||
if (!force) {
|
|
||||||
// Don't draw when FPS is 0
|
|
||||||
if (this.targetFps === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit FPS
|
|
||||||
if (this.targetFps < 60) {
|
|
||||||
const currentTime = performance.now();
|
|
||||||
const timeSinceLastFrame = currentTime - this.lastFrameTime;
|
|
||||||
if (timeSinceLastFrame < this.frameInterval) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.lastFrameTime = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const gl = this.gl!;
|
const gl = this.gl!;
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video);
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupRendering() {
|
private setupRendering() {
|
||||||
let animate: any;
|
let frameCallback: any;
|
||||||
|
|
||||||
if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
|
if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
|
||||||
const $video = this.$video;
|
const $video = this.$video;
|
||||||
animate = () => {
|
frameCallback = $video.requestVideoFrameCallback.bind($video);
|
||||||
if (!this.stopped) {
|
|
||||||
this.drawFrame();
|
|
||||||
this.animFrameId = $video.requestVideoFrameCallback(animate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.animFrameId = $video.requestVideoFrameCallback(animate);
|
|
||||||
} else {
|
} else {
|
||||||
animate = () => {
|
frameCallback = requestAnimationFrame;
|
||||||
if (!this.stopped) {
|
}
|
||||||
this.drawFrame();
|
|
||||||
this.animFrameId = requestAnimationFrame(animate);
|
let animate = () => {
|
||||||
|
if (this.stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let draw = true;
|
||||||
|
|
||||||
|
// Don't draw when FPS is 0
|
||||||
|
if (this.targetFps === 0) {
|
||||||
|
draw = false;
|
||||||
|
} else if (this.targetFps < 60) {
|
||||||
|
// Limit FPS
|
||||||
|
const currentTime = performance.now();
|
||||||
|
const timeSinceLastFrame = currentTime - this.lastFrameTime;
|
||||||
|
if (timeSinceLastFrame < this.frameInterval) {
|
||||||
|
draw = false;
|
||||||
|
} else {
|
||||||
|
this.lastFrameTime = currentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.animFrameId = requestAnimationFrame(animate);
|
if (draw) {
|
||||||
|
const gl = this.gl!;
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.$video);
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.animFrameId = frameCallback(animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.animFrameId = frameCallback(animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupShaders() {
|
private setupShaders() {
|
||||||
|
@ -203,6 +203,11 @@ export class NavigationDialogManager {
|
|||||||
$label = $parent.querySelector<HTMLElement>('div')!;
|
$label = $parent.querySelector<HTMLElement>('div')!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce width if it has <optgroup>
|
||||||
|
if ($select.querySelector('optgroup')) {
|
||||||
|
width -= 15;
|
||||||
|
}
|
||||||
|
|
||||||
// Set min-width
|
// Set min-width
|
||||||
$label.style.minWidth = width + 'px';
|
$label.style.minWidth = width + 'px';
|
||||||
$parent.dataset.calculated = 'true';
|
$parent.dataset.calculated = 'true';
|
||||||
@ -234,7 +239,7 @@ export class NavigationDialogManager {
|
|||||||
} else if (keyCode === 'Enter' || keyCode === 'NumpadEnter' || keyCode === 'Space') {
|
} else if (keyCode === 'Enter' || keyCode === 'NumpadEnter' || keyCode === 'Space') {
|
||||||
if (!($target instanceof HTMLInputElement && $target.type === 'text')) {
|
if (!($target instanceof HTMLInputElement && $target.type === 'text')) {
|
||||||
handled = true;
|
handled = true;
|
||||||
$target.dispatchEvent(new MouseEvent('click'));
|
$target.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||||
}
|
}
|
||||||
} else if (keyCode === 'Escape') {
|
} else if (keyCode === 'Escape') {
|
||||||
handled = true;
|
handled = true;
|
||||||
@ -361,7 +366,7 @@ export class NavigationDialogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (releasedButton === GamepadKey.A) {
|
if (releasedButton === GamepadKey.A) {
|
||||||
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent('click'));
|
document.activeElement && document.activeElement.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||||
return;
|
return;
|
||||||
} else if (releasedButton === GamepadKey.B) {
|
} else if (releasedButton === GamepadKey.B) {
|
||||||
this.hide();
|
this.hide();
|
||||||
|
@ -1044,13 +1044,37 @@ export class SettingsNavigationDialog extends NavigationDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderServerSetting(setting: SettingTabContentItem): HTMLElement {
|
private renderServerSetting(setting: SettingTabContentItem): HTMLElement {
|
||||||
let selectedValue;
|
let selectedValue =getPref(PrefKey.SERVER_REGION);
|
||||||
|
|
||||||
|
const continents: Record<ServerContinent, {
|
||||||
|
label: string,
|
||||||
|
children?: HTMLOptionElement[],
|
||||||
|
}> = {
|
||||||
|
'america-north': {
|
||||||
|
label: t('continent-north-america'),
|
||||||
|
},
|
||||||
|
'america-south': {
|
||||||
|
label: t('continent-south-america'),
|
||||||
|
},
|
||||||
|
'asia': {
|
||||||
|
label: t('continent-asia'),
|
||||||
|
},
|
||||||
|
'australia': {
|
||||||
|
label: t('continent-australia'),
|
||||||
|
},
|
||||||
|
'europe': {
|
||||||
|
label: t('continent-europe'),
|
||||||
|
},
|
||||||
|
'other': {
|
||||||
|
label: t('other'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const $control = CE<HTMLSelectElement>('select', {
|
const $control = CE<HTMLSelectElement>('select', {
|
||||||
id: `bx_setting_${setting.pref}`,
|
id: `bx_setting_${setting.pref}`,
|
||||||
title: setting.label,
|
title: setting.label,
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
});
|
});
|
||||||
$control.name = $control.id;
|
$control.name = $control.id;
|
||||||
|
|
||||||
$control.addEventListener('input', (e: Event) => {
|
$control.addEventListener('input', (e: Event) => {
|
||||||
@ -1058,8 +1082,6 @@ export class SettingsNavigationDialog extends NavigationDialog {
|
|||||||
this.onGlobalSettingChanged(e);
|
this.onGlobalSettingChanged(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
selectedValue = getPref(PrefKey.SERVER_REGION);
|
|
||||||
|
|
||||||
setting.options = {};
|
setting.options = {};
|
||||||
for (const regionName in STATES.serverRegions) {
|
for (const regionName in STATES.serverRegions) {
|
||||||
const region = STATES.serverRegions[regionName];
|
const region = STATES.serverRegions[regionName];
|
||||||
@ -1076,15 +1098,29 @@ export class SettingsNavigationDialog extends NavigationDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setting.options[value] = label;
|
setting.options[value] = label;
|
||||||
|
|
||||||
|
const $option = CE<HTMLOptionElement>('option', {value: value}, label);
|
||||||
|
const continent = continents[region.contintent];
|
||||||
|
if (!continent.children) {
|
||||||
|
continent.children = [];
|
||||||
|
}
|
||||||
|
continent.children.push($option);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const value in setting.options) {
|
const fragment = document.createDocumentFragment();
|
||||||
const label = setting.options[value];
|
let key: keyof typeof continents;
|
||||||
|
for (key in continents) {
|
||||||
|
const continent = continents[key];
|
||||||
|
if (!continent.children) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const $option = CE('option', {value: value}, label);
|
fragment.appendChild(CE('optgroup', {
|
||||||
$control.appendChild($option);
|
label: continent.label,
|
||||||
|
}, ...continent.children));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$control.appendChild(fragment);
|
||||||
$control.disabled = Object.keys(STATES.serverRegions).length === 0;
|
$control.disabled = Object.keys(STATES.serverRegions).length === 0;
|
||||||
|
|
||||||
// Select preferred region
|
// Select preferred region
|
||||||
|
16
src/types/index.d.ts
vendored
16
src/types/index.d.ts
vendored
@ -21,14 +21,24 @@ interface Window {
|
|||||||
|
|
||||||
interface NavigatorBattery extends Navigator {
|
interface NavigatorBattery extends Navigator {
|
||||||
getBattery: () => Promise<{
|
getBattery: () => Promise<{
|
||||||
charging: boolean,
|
charging: boolean;
|
||||||
level: float,
|
level: float;
|
||||||
}>,
|
}>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServerContinent = 'america-north' | 'america-south' | 'asia' | 'australia' | 'europe' | 'other';
|
||||||
|
type ServerRegion = {
|
||||||
|
baseUri: string;
|
||||||
|
isDefault: boolean;
|
||||||
|
name: string;
|
||||||
|
shortName: string;
|
||||||
|
|
||||||
|
contintent: ServerContinent;
|
||||||
|
};
|
||||||
|
|
||||||
type BxStates = {
|
type BxStates = {
|
||||||
supportedRegion: boolean;
|
supportedRegion: boolean;
|
||||||
serverRegions: any;
|
serverRegions: Record<string, ServerRegion>;
|
||||||
selectedRegion: any;
|
selectedRegion: any;
|
||||||
gsToken: string;
|
gsToken: string;
|
||||||
isSignedIn: boolean;
|
isSignedIn: boolean;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export abstract class LocalDb {
|
export abstract class LocalDb {
|
||||||
static readonly DB_NAME = 'BetterXcloud';
|
static readonly DB_NAME = 'BetterXcloud';
|
||||||
static readonly DB_VERSION = 1;
|
static readonly DB_VERSION = 2;
|
||||||
|
|
||||||
private db: any;
|
protected db!: IDBDatabase;
|
||||||
|
|
||||||
protected open() {
|
protected open() {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
@ -12,7 +12,7 @@ export abstract class LocalDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const request = window.indexedDB.open(LocalDb.DB_NAME, LocalDb.DB_VERSION);
|
const request = window.indexedDB.open(LocalDb.DB_NAME, LocalDb.DB_VERSION);
|
||||||
request.onupgradeneeded = this.onUpgradeNeeded;
|
request.onupgradeneeded = this.onUpgradeNeeded.bind(this);
|
||||||
|
|
||||||
request.onerror = e => {
|
request.onerror = e => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
@ -29,7 +29,7 @@ export abstract class LocalDb {
|
|||||||
|
|
||||||
protected abstract onUpgradeNeeded(e: IDBVersionChangeEvent): void;
|
protected abstract onUpgradeNeeded(e: IDBVersionChangeEvent): void;
|
||||||
|
|
||||||
protected table(name: string, type: string): Promise<IDBObjectStore> {
|
protected table(name: string, type: IDBTransactionMode): Promise<IDBObjectStore> {
|
||||||
const transaction = this.db.transaction(name, type || 'readonly');
|
const transaction = this.db.transaction(name, type || 'readonly');
|
||||||
const table = transaction.objectStore(name);
|
const table = transaction.objectStore(name);
|
||||||
|
|
||||||
|
@ -18,79 +18,85 @@ export class MkbPresetsDb extends LocalDb {
|
|||||||
BxLogger.info(this.LOG_TAG, 'constructor()');
|
BxLogger.info(this.LOG_TAG, 'constructor()');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createTable(db: IDBDatabase) {
|
||||||
|
const presets = db.createObjectStore(this.TABLE_PRESETS, {
|
||||||
|
keyPath: 'id',
|
||||||
|
autoIncrement: true,
|
||||||
|
});
|
||||||
|
presets.createIndex('name_idx', 'name');
|
||||||
|
}
|
||||||
|
|
||||||
protected onUpgradeNeeded(e: IDBVersionChangeEvent): void {
|
protected onUpgradeNeeded(e: IDBVersionChangeEvent): void {
|
||||||
const db = (e.target! as any).result;
|
const db = (e.target! as any).result as IDBDatabase;
|
||||||
switch (e.oldVersion) {
|
|
||||||
case 0: {
|
if (db.objectStoreNames.contains('undefined')) {
|
||||||
const presets = db.createObjectStore(this.TABLE_PRESETS, {
|
db.deleteObjectStore('undefined');
|
||||||
keyPath: 'id',
|
}
|
||||||
autoIncrement: true,
|
|
||||||
});
|
if (!db.objectStoreNames.contains(this.TABLE_PRESETS)) {
|
||||||
presets.createIndex('name_idx', 'name');
|
this.createTable(db);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private presetsTable() {
|
private async presetsTable() {
|
||||||
return this.open()
|
await this.open();
|
||||||
.then(() => this.table(this.TABLE_PRESETS, 'readwrite'))
|
return await this.table(this.TABLE_PRESETS, 'readwrite');
|
||||||
}
|
}
|
||||||
|
|
||||||
newPreset(name: string, data: any) {
|
async newPreset(name: string, data: any) {
|
||||||
return this.presetsTable()
|
const table = await this.presetsTable();
|
||||||
.then(table => this.add(table, {name, data}))
|
const [, id] = await this.add(table, { name, data });
|
||||||
.then(([table, id]) => new Promise<number>(resolve => resolve(id)));
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePreset(preset: MkbStoredPreset) {
|
async updatePreset(preset: MkbStoredPreset) {
|
||||||
return this.presetsTable()
|
const table = await this.presetsTable();
|
||||||
.then(table => this.put(table, preset))
|
const [, id] = await this.put(table, preset);
|
||||||
.then(([table, id]) => new Promise(resolve => resolve(id)));
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePreset(id: number) {
|
async deletePreset(id: number) {
|
||||||
return this.presetsTable()
|
const table = await this.presetsTable();
|
||||||
.then(table => this.delete(table, id))
|
await this.delete(table, id);
|
||||||
.then(([table, id]) => new Promise(resolve => resolve(id)));
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPreset(id: number): Promise<MkbStoredPreset> {
|
async getPreset(id: number): Promise<MkbStoredPreset> {
|
||||||
return this.presetsTable()
|
const table = await this.presetsTable();
|
||||||
.then(table => this.get(table, id))
|
const [, preset] = await this.get(table, id);
|
||||||
.then(([table, preset]) => new Promise(resolve => resolve(preset)));
|
|
||||||
|
return preset;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPresets(): Promise<MkbStoredPresets> {
|
async getPresets(): Promise<MkbStoredPresets> {
|
||||||
return this.presetsTable()
|
const table = await this.presetsTable();
|
||||||
.then(table => this.count(table))
|
const [, count] = await this.count(table);
|
||||||
.then(([table, count]) => {
|
|
||||||
if (count > 0) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
this.getAll(table)
|
|
||||||
.then(([table, items]) => {
|
|
||||||
const presets: MkbStoredPresets = {};
|
|
||||||
items.forEach((item: MkbStoredPreset) => (presets[item.id!] = item));
|
|
||||||
resolve(presets);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create "Default" preset when the table is empty
|
// Return stored presets
|
||||||
const preset: MkbStoredPreset = {
|
if (count > 0) {
|
||||||
name: t('default'),
|
const [, items] = await this.getAll(table);
|
||||||
data: MkbPreset.DEFAULT_PRESET,
|
const presets: MkbStoredPresets = {};
|
||||||
}
|
items.forEach((item: MkbStoredPreset) => (presets[item.id!] = item));
|
||||||
|
|
||||||
return new Promise<MkbStoredPresets>(resolve => {
|
return presets;
|
||||||
this.add(table, preset)
|
}
|
||||||
.then(([table, id]) => {
|
|
||||||
preset.id = id;
|
|
||||||
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, id);
|
|
||||||
|
|
||||||
resolve({[id]: preset});
|
// Create "Default" preset when the table is empty
|
||||||
});
|
const preset: MkbStoredPreset = {
|
||||||
});
|
name: t('default'),
|
||||||
});
|
data: MkbPreset.DEFAULT_PRESET,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [, id] = await this.add(table, preset);
|
||||||
|
|
||||||
|
preset.id = id;
|
||||||
|
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
[id]: preset,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ export class ScreenshotManager {
|
|||||||
const canvasContext = this.canvasContext;
|
const canvasContext = this.canvasContext;
|
||||||
|
|
||||||
if ($player instanceof HTMLCanvasElement) {
|
if ($player instanceof HTMLCanvasElement) {
|
||||||
streamPlayer.getWebGL2Player().drawFrame(true);
|
streamPlayer.getWebGL2Player().forceDrawFrame();
|
||||||
}
|
}
|
||||||
canvasContext.drawImage($player, 0, 0, $canvas.width, $canvas.height);
|
canvasContext.drawImage($player, 0, 0, $canvas.width, $canvas.height);
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ export interface BxSelectSettingElement extends HTMLSelectElement, BxBaseSetting
|
|||||||
export class SettingElement {
|
export class SettingElement {
|
||||||
static #renderOptions(key: string, setting: PreferenceSetting, currentValue: any, onChange: any): BxSelectSettingElement {
|
static #renderOptions(key: string, setting: PreferenceSetting, currentValue: any, onChange: any): BxSelectSettingElement {
|
||||||
const $control = CE<BxSelectSettingElement>('select', {
|
const $control = CE<BxSelectSettingElement>('select', {
|
||||||
// title: setting.label,
|
// title: setting.label,
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
let $parent: HTMLElement;
|
let $parent: HTMLElement;
|
||||||
if (setting.optionsGroup) {
|
if (setting.optionsGroup) {
|
||||||
@ -64,10 +64,10 @@ export class SettingElement {
|
|||||||
|
|
||||||
static #renderMultipleOptions(key: string, setting: PreferenceSetting, currentValue: any, onChange: any, params: MultipleOptionsParams={}): BxSelectSettingElement {
|
static #renderMultipleOptions(key: string, setting: PreferenceSetting, currentValue: any, onChange: any, params: MultipleOptionsParams={}): BxSelectSettingElement {
|
||||||
const $control = CE<BxSelectSettingElement>('select', {
|
const $control = CE<BxSelectSettingElement>('select', {
|
||||||
// title: setting.label,
|
// title: setting.label,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (params && params.size) {
|
if (params && params.size) {
|
||||||
$control.setAttribute('size', params.size.toString());
|
$control.setAttribute('size', params.size.toString());
|
||||||
@ -164,6 +164,14 @@ export class SettingElement {
|
|||||||
const MAX = options.reverse ? -setting.min! : setting.max!;
|
const MAX = options.reverse ? -setting.min! : setting.max!;
|
||||||
const STEPS = Math.max(setting.steps || 1, 1);
|
const STEPS = Math.max(setting.steps || 1, 1);
|
||||||
|
|
||||||
|
let intervalId: number | null;
|
||||||
|
let isHolding = false;
|
||||||
|
|
||||||
|
const clearIntervalId = () => {
|
||||||
|
intervalId && clearInterval(intervalId);
|
||||||
|
intervalId = null;
|
||||||
|
}
|
||||||
|
|
||||||
const renderTextValue = (value: any) => {
|
const renderTextValue = (value: any) => {
|
||||||
value = parseInt(value as string);
|
value = parseInt(value as string);
|
||||||
|
|
||||||
@ -182,6 +190,10 @@ export class SettingElement {
|
|||||||
const updateButtonsVisibility = () => {
|
const updateButtonsVisibility = () => {
|
||||||
$btnDec.classList.toggle('bx-inactive', controlValue === MIN);
|
$btnDec.classList.toggle('bx-inactive', controlValue === MIN);
|
||||||
$btnInc.classList.toggle('bx-inactive', controlValue === MAX);
|
$btnInc.classList.toggle('bx-inactive', controlValue === MAX);
|
||||||
|
|
||||||
|
if (controlValue === MIN || controlValue === MAX) {
|
||||||
|
clearIntervalId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const $wrapper = CE<BxHtmlSettingElement>('div', {'class': 'bx-number-stepper', id: `bx_setting_${key}`},
|
const $wrapper = CE<BxHtmlSettingElement>('div', {'class': 'bx-number-stepper', id: `bx_setting_${key}`},
|
||||||
@ -212,7 +224,7 @@ export class SettingElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$range = CE<HTMLInputElement>('input', {
|
$range = CE<HTMLInputElement>('input', {
|
||||||
id: `bx_setting_${key}`,
|
id: `bx_inp_setting_${key}`,
|
||||||
type: 'range',
|
type: 'range',
|
||||||
min: MIN,
|
min: MIN,
|
||||||
max: MAX,
|
max: MAX,
|
||||||
@ -273,18 +285,7 @@ export class SettingElement {
|
|||||||
|
|
||||||
updateButtonsVisibility();
|
updateButtonsVisibility();
|
||||||
|
|
||||||
let interval: number;
|
const buttonPressed = (e: Event, $btn: HTMLElement) => {
|
||||||
let isHolding = false;
|
|
||||||
|
|
||||||
const onClick = (e: Event) => {
|
|
||||||
if (isHolding) {
|
|
||||||
e.preventDefault();
|
|
||||||
isHolding = false;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $btn = e.target as HTMLElement;
|
|
||||||
let value = parseInt(controlValue);
|
let value = parseInt(controlValue);
|
||||||
|
|
||||||
const btnType = $btn.dataset.type;
|
const btnType = $btn.dataset.type;
|
||||||
@ -300,27 +301,43 @@ export class SettingElement {
|
|||||||
$text.textContent = renderTextValue(value);
|
$text.textContent = renderTextValue(value);
|
||||||
$range && ($range.value = value.toString());
|
$range && ($range.value = value.toString());
|
||||||
|
|
||||||
isHolding = false;
|
onChange && onChange(e, value);
|
||||||
!(e as any).ignoreOnChange && onChange && onChange(e, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onMouseDown = (e: PointerEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
isHolding = true;
|
|
||||||
|
|
||||||
const args = arguments;
|
|
||||||
interval && clearInterval(interval);
|
|
||||||
interval = window.setInterval(() => {
|
|
||||||
e.target && BxEvent.dispatch(e.target as HTMLElement, 'click', {
|
|
||||||
arguments: args,
|
|
||||||
});
|
|
||||||
}, 200);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = (e: PointerEvent) => {
|
const onClick = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (isHolding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $btn = (e.target as HTMLElement).closest('button') as HTMLElement;
|
||||||
|
$btn && buttonPressed(e, $btn);
|
||||||
|
|
||||||
|
clearIntervalId();
|
||||||
|
isHolding = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPointerDown = (e: PointerEvent) => {
|
||||||
|
clearIntervalId();
|
||||||
|
|
||||||
|
const $btn = (e.target as HTMLElement).closest('button') as HTMLElement;
|
||||||
|
if (!$btn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isHolding = true;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
interval && clearInterval(interval);
|
intervalId = window.setInterval((e: Event) => {
|
||||||
|
buttonPressed(e, $btn);
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
window.addEventListener('pointerup', onPointerUp, {once: true});
|
||||||
|
window.addEventListener('pointercancel', onPointerUp, {once: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPointerUp = (e: PointerEvent) => {
|
||||||
|
clearIntervalId();
|
||||||
isHolding = false;
|
isHolding = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -332,18 +349,11 @@ export class SettingElement {
|
|||||||
$range.value = options.reverse ? -value : value;
|
$range.value = options.reverse ? -value : value;
|
||||||
};
|
};
|
||||||
|
|
||||||
$btnDec.addEventListener('click', onClick);
|
$wrapper.addEventListener('click', onClick);
|
||||||
$btnDec.addEventListener('pointerdown', onMouseDown);
|
$wrapper.addEventListener('pointerdown', onPointerDown);
|
||||||
$btnDec.addEventListener('pointerup', onMouseUp);
|
$wrapper.addEventListener('contextmenu', onContextMenu);
|
||||||
$btnDec.addEventListener('contextmenu', onContextMenu);
|
|
||||||
|
|
||||||
$btnInc.addEventListener('click', onClick);
|
|
||||||
$btnInc.addEventListener('pointerdown', onMouseDown);
|
|
||||||
$btnInc.addEventListener('pointerup', onMouseUp);
|
|
||||||
$btnInc.addEventListener('contextmenu', onContextMenu);
|
|
||||||
|
|
||||||
setNearby($wrapper, {
|
setNearby($wrapper, {
|
||||||
focus: $range || $btnInc,
|
focus: options.hideSlider ? $btnInc : $range,
|
||||||
})
|
})
|
||||||
|
|
||||||
return $wrapper;
|
return $wrapper;
|
||||||
|
@ -404,7 +404,7 @@ export class GlobalSettingsStorage extends BaseSettingsStorage {
|
|||||||
|
|
||||||
let text = +(1000 / value).toFixed(2) + ' Hz';
|
let text = +(1000 / value).toFixed(2) + ' Hz';
|
||||||
if (value === 4) {
|
if (value === 4) {
|
||||||
text = `${t('default')} (${text})`;
|
text = `${text} (${t('default')})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
|
@ -67,6 +67,11 @@ const Texts = {
|
|||||||
"confirm-reload-stream": "Do you want to refresh the stream?",
|
"confirm-reload-stream": "Do you want to refresh the stream?",
|
||||||
"connected": "Connected",
|
"connected": "Connected",
|
||||||
"console-connect": "Connect",
|
"console-connect": "Connect",
|
||||||
|
"continent-asia": "Asia",
|
||||||
|
"continent-australia": "Australia",
|
||||||
|
"continent-europe": "Europe",
|
||||||
|
"continent-north-america": "North America",
|
||||||
|
"continent-south-america": "South America",
|
||||||
"contrast": "Contrast",
|
"contrast": "Contrast",
|
||||||
"controller": "Controller",
|
"controller": "Controller",
|
||||||
"controller-friendly-ui": "Controller-friendly UI",
|
"controller-friendly-ui": "Controller-friendly UI",
|
||||||
@ -170,7 +175,7 @@ const Texts = {
|
|||||||
(e: any) => `${e.version} 버전 사용가능`,
|
(e: any) => `${e.version} 버전 사용가능`,
|
||||||
(e: any) => `Dostępna jest nowa wersja ${e.version}`,
|
(e: any) => `Dostępna jest nowa wersja ${e.version}`,
|
||||||
(e: any) => `Versão ${e.version} disponível`,
|
(e: any) => `Versão ${e.version} disponível`,
|
||||||
,
|
(e: any) => `Версия ${e.version} доступна`,
|
||||||
(e: any) => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,
|
(e: any) => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,
|
||||||
(e: any) => `${e.version} sayılı yeni sürüm mevcut`,
|
(e: any) => `${e.version} sayılı yeni sürüm mevcut`,
|
||||||
(e: any) => `Доступна версія ${e.version}`,
|
(e: any) => `Доступна версія ${e.version}`,
|
||||||
|
@ -14,21 +14,31 @@ import { PrefKey } from "@/enums/pref-keys";
|
|||||||
import { getPref, StreamResolution, StreamTouchController } from "./settings-storages/global-settings-storage";
|
import { getPref, StreamResolution, StreamTouchController } from "./settings-storages/global-settings-storage";
|
||||||
|
|
||||||
export class XcloudInterceptor {
|
export class XcloudInterceptor {
|
||||||
private static readonly SERVER_EMOJIS = {
|
private static readonly SERVER_EXTRA_INFO: Record<string, [string, ServerContinent]> = {
|
||||||
AustraliaEast: '🇦🇺',
|
// North America
|
||||||
AustraliaSouthEast: '🇦🇺',
|
EastUS: ['🇺🇸', 'america-north'],
|
||||||
BrazilSouth: '🇧🇷',
|
EastUS2: ['🇺🇸', 'america-north'],
|
||||||
EastUS: '🇺🇸',
|
NorthCentralUs: ['🇺🇸', 'america-north'],
|
||||||
EastUS2: '🇺🇸',
|
SouthCentralUS: ['🇺🇸', 'america-north'],
|
||||||
JapanEast: '🇯🇵',
|
WestUS: ['🇺🇸', 'america-north'],
|
||||||
KoreaCentral: '🇰🇷',
|
WestUS2: ['🇺🇸', 'america-north'],
|
||||||
MexicoCentral: '🇲🇽',
|
MexicoCentral: ['🇲🇽', 'america-north'],
|
||||||
NorthCentralUs: '🇺🇸',
|
|
||||||
SouthCentralUS: '🇺🇸',
|
// South America
|
||||||
UKSouth: '🇬🇧',
|
BrazilSouth: ['🇧🇷', 'america-south'],
|
||||||
WestEurope: '🇪🇺',
|
|
||||||
WestUS: '🇺🇸',
|
// Asia
|
||||||
WestUS2: '🇺🇸',
|
JapanEast: ['🇯🇵', 'asia'],
|
||||||
|
KoreaCentral: ['🇰🇷', 'asia'],
|
||||||
|
|
||||||
|
// Australia
|
||||||
|
AustraliaEast: ['🇦🇺', 'australia'],
|
||||||
|
AustraliaSouthEast: ['🇦🇺', 'australia'],
|
||||||
|
|
||||||
|
// Europe
|
||||||
|
SwedenCentral: ['🇸🇪', 'europe'],
|
||||||
|
UKSouth: ['🇬🇧', 'europe'],
|
||||||
|
WestEurope: ['🇪🇺', 'europe'],
|
||||||
};
|
};
|
||||||
|
|
||||||
private static async handleLogin(request: RequestInfo | URL, init?: RequestInit) {
|
private static async handleLogin(request: RequestInfo | URL, init?: RequestInit) {
|
||||||
@ -52,10 +62,11 @@ export class XcloudInterceptor {
|
|||||||
|
|
||||||
// Get server list
|
// Get server list
|
||||||
const serverRegex = /\/\/(\w+)\./;
|
const serverRegex = /\/\/(\w+)\./;
|
||||||
const serverEmojis = XcloudInterceptor.SERVER_EMOJIS;
|
const serverExtra = XcloudInterceptor.SERVER_EXTRA_INFO;
|
||||||
|
|
||||||
for (let region of obj.offeringSettings.regions) {
|
let region: ServerRegion;
|
||||||
const regionName = region.name as keyof typeof serverEmojis;
|
for (region of obj.offeringSettings.regions) {
|
||||||
|
const regionName = region.name as keyof typeof serverExtra;
|
||||||
let shortName = region.name;
|
let shortName = region.name;
|
||||||
|
|
||||||
if (region.isDefault) {
|
if (region.isDefault) {
|
||||||
@ -65,8 +76,11 @@ export class XcloudInterceptor {
|
|||||||
let match = serverRegex.exec(region.baseUri);
|
let match = serverRegex.exec(region.baseUri);
|
||||||
if (match) {
|
if (match) {
|
||||||
shortName = match[1];
|
shortName = match[1];
|
||||||
if (serverEmojis[regionName]) {
|
if (serverExtra[regionName]) {
|
||||||
shortName = serverEmojis[regionName] + ' ' + shortName;
|
shortName = serverExtra[regionName][0] + ' ' + shortName;
|
||||||
|
region.contintent = serverExtra[regionName][1];
|
||||||
|
} else {
|
||||||
|
region.contintent = 'other';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ export class XhomeInterceptor {
|
|||||||
];
|
];
|
||||||
|
|
||||||
XhomeInterceptor.consoleAddrs = {};
|
XhomeInterceptor.consoleAddrs = {};
|
||||||
for (const pair in pairs) {
|
for (const pair of pairs) {
|
||||||
const [keyAddr, keyPort] = pair;
|
const [keyAddr, keyPort] = pair;
|
||||||
if (serverDetails[keyAddr]) {
|
if (serverDetails[keyAddr]) {
|
||||||
const port = serverDetails[keyPort];
|
const port = serverDetails[keyPort];
|
||||||
|
Reference in New Issue
Block a user