Compare commits

..

9 Commits

Author SHA1 Message Date
redphx
4d49639622 Bump version to 5.9.2 2024-10-24 20:58:53 +07:00
redphx
22f1ebdd08 Fix Remote Play not working when using different network (#538) 2024-10-24 20:38:01 +07:00
redphx
bae51eff3d Bump version to 5.9.1 2024-10-23 21:09:26 +07:00
redphx
adc9897210 Update translations 2024-10-23 21:08:20 +07:00
redphx
53442557e1 Fix Virtual Controller Remapper's bug (contd) 2024-10-23 20:51:04 +07:00
redphx
5b67b4c37d Fix Virtual Controller Remapper's bug (contd) 2024-10-23 20:14:10 +07:00
redphx
5a06933143 Update dists 2024-10-23 20:03:26 +07:00
redphx
6440c91cdf Fix Virtual Controller Remapper's bug 2024-10-23 20:00:27 +07:00
redphx
b06dc6e219 Update polling rate's default text 2024-10-22 20:47:45 +07:00
9 changed files with 322 additions and 307 deletions

View File

@@ -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.2
// @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.2", 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,
@@ -403,7 +403,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}`,
@@ -1393,7 +1393,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 +2381,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 +2390,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 +2438,49 @@ class MkbPresetsDb extends LocalDb {
super(); super();
BxLogger.info(this.LOG_TAG, "constructor()"); BxLogger.info(this.LOG_TAG, "constructor()");
} }
onUpgradeNeeded(e) { createTable(db) {
let db = e.target.result;
switch (e.oldVersion) {
case 0: {
db.createObjectStore(this.TABLE_PRESETS, { db.createObjectStore(this.TABLE_PRESETS, {
keyPath: "id", keyPath: "id",
autoIncrement: !0 autoIncrement: !0
}).createIndex("name_idx", "name"); }).createIndex("name_idx", "name");
break;
} }
onUpgradeNeeded(e) {
let db = e.target.result;
if (db.objectStoreNames.contains("undefined")) db.deleteObjectStore("undefined");
if (!db.objectStoreNames.contains(this.TABLE_PRESETS)) this.createTable(db);
} }
async presetsTable() {
return await this.open(), await this.table(this.TABLE_PRESETS, "readwrite");
} }
presetsTable() { async newPreset(name, data) {
return this.open().then(() => this.table(this.TABLE_PRESETS, "readwrite")); let table = await this.presetsTable(), [, id] = await this.add(table, { name, data });
return id;
} }
newPreset(name, data) { async updatePreset(preset) {
return this.presetsTable().then((table) => this.add(table, { name, data })).then(([table, id]) => new Promise((resolve) => resolve(id))); let table = await this.presetsTable(), [, id] = await this.put(table, preset);
return id;
} }
updatePreset(preset) { async deletePreset(id) {
return this.presetsTable().then((table) => this.put(table, preset)).then(([table, id]) => new Promise((resolve) => resolve(id))); let table = await this.presetsTable();
return await this.delete(table, id), id;
} }
deletePreset(id) { async getPreset(id) {
return this.presetsTable().then((table) => this.delete(table, id)).then(([table, id2]) => new Promise((resolve) => resolve(id2))); let table = await this.presetsTable(), [, preset] = await this.get(table, id);
return preset;
} }
getPreset(id) { async getPresets() {
return this.presetsTable().then((table) => this.get(table, id)).then(([table, preset]) => new Promise((resolve) => resolve(preset))); 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;
} }
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 = { let preset = {
name: t("default"), name: t("default"),
data: MkbPreset.DEFAULT_PRESET data: MkbPreset.DEFAULT_PRESET
}, [, id] = await this.add(table, preset);
return preset.id = id, setPref("mkb_default_preset_id", id), {
[id]: 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 = {
@@ -3176,7 +3174,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 +3188,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 +3202,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 +3219,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 +3251,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.STATE.currentPresetId, $fragment.appendChild($options); $options.selected = parseInt(id) === this.states.currentPresetId, fragment.appendChild($options);
} }
this.$presetsSelect.appendChild($fragment); this.$presetsSelect.appendChild(fragment);
let activated = defaultPresetId === this.STATE.currentPresetId; let activated = defaultPresetId === 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); this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate"), !this.states.isEditing && this.switchPreset(this.states.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 +3297,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 +3310,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 +3321,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 +3331,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 +3354,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 +3371,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 +3386,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();
}); });

View File

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

View File

@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name Better xCloud // @name Better xCloud
// @namespace https://github.com/redphx // @namespace https://github.com/redphx
// @version 5.9.0 // @version 5.9.2
// @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.2", 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,
@@ -426,7 +426,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}`,
@@ -1416,7 +1416,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;
} }
} }
@@ -2656,7 +2656,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 +2665,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 +2713,49 @@ class MkbPresetsDb extends LocalDb {
super(); super();
BxLogger.info(this.LOG_TAG, "constructor()"); BxLogger.info(this.LOG_TAG, "constructor()");
} }
onUpgradeNeeded(e) { createTable(db) {
let db = e.target.result;
switch (e.oldVersion) {
case 0: {
db.createObjectStore(this.TABLE_PRESETS, { db.createObjectStore(this.TABLE_PRESETS, {
keyPath: "id", keyPath: "id",
autoIncrement: !0 autoIncrement: !0
}).createIndex("name_idx", "name"); }).createIndex("name_idx", "name");
break;
} }
onUpgradeNeeded(e) {
let db = e.target.result;
if (db.objectStoreNames.contains("undefined")) db.deleteObjectStore("undefined");
if (!db.objectStoreNames.contains(this.TABLE_PRESETS)) this.createTable(db);
} }
async presetsTable() {
return await this.open(), await this.table(this.TABLE_PRESETS, "readwrite");
} }
presetsTable() { async newPreset(name, data) {
return this.open().then(() => this.table(this.TABLE_PRESETS, "readwrite")); let table = await this.presetsTable(), [, id2] = await this.add(table, { name, data });
return id2;
} }
newPreset(name, data) { async updatePreset(preset) {
return this.presetsTable().then((table) => this.add(table, { name, data })).then(([table, id2]) => new Promise((resolve) => resolve(id2))); let table = await this.presetsTable(), [, id2] = await this.put(table, preset);
return id2;
} }
updatePreset(preset) { async deletePreset(id2) {
return this.presetsTable().then((table) => this.put(table, preset)).then(([table, id2]) => new Promise((resolve) => resolve(id2))); let table = await this.presetsTable();
return await this.delete(table, id2), id2;
} }
deletePreset(id2) { async getPreset(id2) {
return this.presetsTable().then((table) => this.delete(table, id2)).then(([table, id3]) => new Promise((resolve) => resolve(id3))); let table = await this.presetsTable(), [, preset] = await this.get(table, id2);
return preset;
} }
getPreset(id2) { async getPresets() {
return this.presetsTable().then((table) => this.get(table, id2)).then(([table, preset]) => new Promise((resolve) => resolve(preset))); 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;
} }
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 = { let preset = {
name: t("default"), name: t("default"),
data: MkbPreset.DEFAULT_PRESET data: MkbPreset.DEFAULT_PRESET
}, [, id2] = await this.add(table, preset);
return preset.id = id2, setPref("mkb_default_preset_id", id2), {
[id2]: 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 = {
@@ -3457,7 +3455,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 +3469,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 +3483,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 +3500,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 +3532,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.STATE.currentPresetId, $fragment.appendChild($options); $options.selected = parseInt(id2) === this.states.currentPresetId, fragment.appendChild($options);
} }
this.$presetsSelect.appendChild($fragment); this.$presetsSelect.appendChild(fragment);
let activated = defaultPresetId === this.STATE.currentPresetId; let activated = defaultPresetId === 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); this.$activateButton.disabled = activated, this.$activateButton.querySelector("span").textContent = activated ? t("activated") : t("activate"), !this.states.isEditing && this.switchPreset(this.states.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 +3578,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 +3591,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 +3602,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 +3612,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 +3635,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 +3652,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 +3667,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();
}); });
@@ -6110,7 +6111,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;

View File

@@ -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,26 +230,25 @@ 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);
}
MkbPresetsDb.getInstance().getPresets().then(presets => { const presets = await MkbPresetsDb.getInstance().getPresets();
this.STATE.presets = presets;
const $fragment = document.createDocumentFragment(); this.states.presets = presets;
const fragment = document.createDocumentFragment();
let defaultPresetId; let defaultPresetId;
if (this.STATE.currentPresetId === 0) { if (this.states.currentPresetId === 0) {
this.STATE.currentPresetId = parseInt(Object.keys(presets)[0]); this.states.currentPresetId = parseInt(Object.keys(presets)[0]);
defaultPresetId = this.STATE.currentPresetId; defaultPresetId = this.states.currentPresetId;
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, defaultPresetId); setPref(PrefKey.MKB_DEFAULT_PRESET_ID, defaultPresetId);
EmulatedMkbHandler.getInstance().refreshPresetData(); EmulatedMkbHandler.getInstance().refreshPresetData();
} else { } else {
@@ -257,30 +263,29 @@ export class MkbRemapper {
} }
const $options = CE<HTMLOptionElement>('option', {value: id}, name); const $options = CE<HTMLOptionElement>('option', {value: id}, name);
$options.selected = parseInt(id) === this.STATE.currentPresetId; $options.selected = parseInt(id) === this.states.currentPresetId;
$fragment.appendChild($options); fragment.appendChild($options);
}; };
this.$presetsSelect.appendChild($fragment); this.$presetsSelect.appendChild(fragment);
// Update state of Activate button // Update state of Activate button
const activated = defaultPresetId === this.STATE.currentPresetId; const activated = defaultPresetId === 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');
!this.STATE.isEditing && this.switchPreset(this.STATE.currentPresetId); !this.states.isEditing && this.switchPreset(this.states.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

View File

@@ -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);

View File

@@ -18,79 +18,85 @@ export class MkbPresetsDb extends LocalDb {
BxLogger.info(this.LOG_TAG, 'constructor()'); BxLogger.info(this.LOG_TAG, 'constructor()');
} }
protected onUpgradeNeeded(e: IDBVersionChangeEvent): void { private createTable(db: IDBDatabase) {
const db = (e.target! as any).result;
switch (e.oldVersion) {
case 0: {
const presets = db.createObjectStore(this.TABLE_PRESETS, { const presets = db.createObjectStore(this.TABLE_PRESETS, {
keyPath: 'id', keyPath: 'id',
autoIncrement: true, autoIncrement: true,
}); });
presets.createIndex('name_idx', 'name'); presets.createIndex('name_idx', 'name');
break;
} }
protected onUpgradeNeeded(e: IDBVersionChangeEvent): void {
const db = (e.target! as any).result as IDBDatabase;
if (db.objectStoreNames.contains('undefined')) {
db.deleteObjectStore('undefined');
}
if (!db.objectStoreNames.contains(this.TABLE_PRESETS)) {
this.createTable(db);
} }
} }
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]) => {
// Return stored presets
if (count > 0) { if (count > 0) {
return new Promise(resolve => { const [, items] = await this.getAll(table);
this.getAll(table)
.then(([table, items]) => {
const presets: MkbStoredPresets = {}; const presets: MkbStoredPresets = {};
items.forEach((item: MkbStoredPreset) => (presets[item.id!] = item)); items.forEach((item: MkbStoredPreset) => (presets[item.id!] = item));
resolve(presets);
}); return presets;
});
} }
// Create "Default" preset when the table is empty // Create "Default" preset when the table is empty
const preset: MkbStoredPreset = { const preset: MkbStoredPreset = {
name: t('default'), name: t('default'),
data: MkbPreset.DEFAULT_PRESET, data: MkbPreset.DEFAULT_PRESET,
} };
const [, id] = await this.add(table, preset);
return new Promise<MkbStoredPresets>(resolve => {
this.add(table, preset)
.then(([table, id]) => {
preset.id = id; preset.id = id;
setPref(PrefKey.MKB_DEFAULT_PRESET_ID, id); setPref(PrefKey.MKB_DEFAULT_PRESET_ID, id);
resolve({[id]: preset}); return {
}); [id]: preset,
}); };
});
} }
} }

View File

@@ -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;

View File

@@ -170,7 +170,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}`,

View File

@@ -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];