Fix Virtual Controller Remapper's bug

This commit is contained in:
redphx 2024-10-23 20:00:27 +07:00
parent b06dc6e219
commit 6440c91cdf
2 changed files with 117 additions and 110 deletions

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

@ -32,65 +32,65 @@ export class MkbPresetsDb extends LocalDb {
} }
} }
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,
}); };
});
} }
} }