mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-08-06 21:28:27 +02:00
6.0
This commit is contained in:
194
src/modules/ui/dialog/profile-manger/controller-shortcuts-manager-dialog.ts
Executable file
194
src/modules/ui/dialog/profile-manger/controller-shortcuts-manager-dialog.ts
Executable file
@@ -0,0 +1,194 @@
|
||||
import { t } from "@/utils/translation";
|
||||
import { BaseProfileManagerDialog } from "./base-profile-manager-dialog";
|
||||
import { CE } from "@/utils/html";
|
||||
import { GamepadKey, GamepadKeyName } from "@/enums/gamepad";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { PrompFont } from "@/enums/prompt-font";
|
||||
import { ShortcutAction } from "@/enums/shortcut-actions";
|
||||
import { deepClone } from "@/utils/global";
|
||||
import { setNearby } from "@/utils/navigation-utils";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import type { ControllerShortcutPresetData, ControllerShortcutPresetRecord } from "@/types/presets";
|
||||
import { ControllerShortcutsTable } from "@/utils/local-db/controller-shortcuts-table";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { SHORTCUT_ACTIONS } from "@/modules/shortcuts/shortcut-actions";
|
||||
|
||||
export class ControllerShortcutsManagerDialog extends BaseProfileManagerDialog<ControllerShortcutPresetRecord> {
|
||||
private static instance: ControllerShortcutsManagerDialog;
|
||||
public static getInstance = () => ControllerShortcutsManagerDialog.instance ?? (ControllerShortcutsManagerDialog.instance = new ControllerShortcutsManagerDialog(t('controller-shortcuts')));
|
||||
// private readonly LOG_TAG = 'ControllerShortcutsManagerDialog';
|
||||
|
||||
protected $content: HTMLElement;
|
||||
private selectActions: Partial<Record<GamepadKey, [HTMLSelectElement, HTMLSelectElement | null]>> = {};
|
||||
|
||||
protected readonly BLANK_PRESET_DATA = {
|
||||
mapping: {},
|
||||
};
|
||||
|
||||
private readonly BUTTONS_ORDER = [
|
||||
GamepadKey.Y, GamepadKey.A, GamepadKey.X, GamepadKey.B,
|
||||
GamepadKey.UP, GamepadKey.DOWN, GamepadKey.LEFT, GamepadKey.RIGHT,
|
||||
GamepadKey.SELECT, GamepadKey.START,
|
||||
GamepadKey.LB, GamepadKey.RB,
|
||||
GamepadKey.LT, GamepadKey.RT,
|
||||
GamepadKey.L3, GamepadKey.R3,
|
||||
];
|
||||
|
||||
constructor(title: string) {
|
||||
super(title, ControllerShortcutsTable.getInstance());
|
||||
|
||||
const PREF_CONTROLLER_FRIENDLY_UI = getPref(PrefKey.UI_CONTROLLER_FRIENDLY);
|
||||
|
||||
// Read actions from localStorage
|
||||
// ControllerShortcut.ACTIONS = ControllerShortcut.getActionsFromStorage();
|
||||
|
||||
const $baseSelect = CE<HTMLSelectElement>('select', { autocomplete: 'off' }, CE('option', { value: '' }, '---'));
|
||||
for (const groupLabel in SHORTCUT_ACTIONS) {
|
||||
const items = SHORTCUT_ACTIONS[groupLabel];
|
||||
if (!items) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $optGroup = CE<HTMLOptGroupElement>('optgroup', { label: groupLabel });
|
||||
for (const action in items) {
|
||||
const crumbs = items[action as keyof typeof items];
|
||||
if (!crumbs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const label = crumbs.join(' ❯ ');
|
||||
const $option = CE<HTMLOptionElement>('option', { value: action }, label);
|
||||
$optGroup.appendChild($option);
|
||||
}
|
||||
|
||||
$baseSelect.appendChild($optGroup);
|
||||
}
|
||||
|
||||
const $content = CE('div', {
|
||||
class: 'bx-controller-shortcuts-manager-container',
|
||||
});
|
||||
|
||||
const onActionChanged = (e: Event) => {
|
||||
const $target = e.target as HTMLSelectElement;
|
||||
|
||||
// const profile = $selectProfile.value;
|
||||
// const button: unknown = $target.dataset.button;
|
||||
const action = $target.value as ShortcutAction;
|
||||
|
||||
if (!PREF_CONTROLLER_FRIENDLY_UI) {
|
||||
const $fakeSelect = $target.previousElementSibling! as HTMLSelectElement;
|
||||
let fakeText = '---';
|
||||
if (action) {
|
||||
const $selectedOption = $target.options[$target.selectedIndex];
|
||||
const $optGroup = $selectedOption.parentElement as HTMLOptGroupElement;
|
||||
fakeText = $optGroup.label + ' ❯ ' + $selectedOption.text;
|
||||
}
|
||||
($fakeSelect.firstElementChild as HTMLOptionElement).text = fakeText;
|
||||
}
|
||||
|
||||
// Update preset
|
||||
if (!(e as any).ignoreOnChange) {
|
||||
this.updatePreset();
|
||||
}
|
||||
};
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
fragment.appendChild(CE('p', {class: 'bx-shortcut-note'},
|
||||
CE('span', {class: 'bx-prompt'}, PrompFont.HOME),
|
||||
': ' + t('controller-shortcuts-xbox-note'),
|
||||
));
|
||||
|
||||
for (const button of this.BUTTONS_ORDER) {
|
||||
const prompt = GamepadKeyName[button][1];
|
||||
|
||||
const $row = CE('div', {
|
||||
class: 'bx-shortcut-row',
|
||||
_nearby: {
|
||||
orientation: 'horizontal',
|
||||
},
|
||||
});
|
||||
const $label = CE('label', {class: 'bx-prompt'}, `${PrompFont.HOME}${prompt}`);
|
||||
const $div = CE('div', {class: 'bx-shortcut-actions'});
|
||||
|
||||
let $fakeSelect: HTMLSelectElement | null = null;
|
||||
if (!PREF_CONTROLLER_FRIENDLY_UI) {
|
||||
$fakeSelect = CE<HTMLSelectElement>('select', { autocomplete: 'off' },
|
||||
CE('option', {}, '---'),
|
||||
);
|
||||
|
||||
$div.appendChild($fakeSelect);
|
||||
}
|
||||
|
||||
const $select = BxSelectElement.create($baseSelect.cloneNode(true) as HTMLSelectElement);
|
||||
$select.dataset.button = button.toString();
|
||||
$select.classList.add('bx-full-width');
|
||||
$select.addEventListener('input', onActionChanged);
|
||||
|
||||
this.selectActions[button] = [$select, $fakeSelect];
|
||||
|
||||
$div.appendChild($select);
|
||||
setNearby($row, {
|
||||
focus: $select,
|
||||
});
|
||||
|
||||
$row.append($label, $div);
|
||||
fragment.appendChild($row);
|
||||
}
|
||||
|
||||
$content.appendChild(fragment);
|
||||
|
||||
this.$content = $content;
|
||||
}
|
||||
|
||||
protected switchPreset(id: number): void {
|
||||
const preset = this.allPresets.data[id];
|
||||
if (!preset) {
|
||||
this.currentPresetId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentPresetId = id;
|
||||
const isDefaultPreset = id <= 0;
|
||||
const actions = preset.data;
|
||||
|
||||
// Reset selects' values
|
||||
let button: unknown;
|
||||
for (button in this.selectActions) {
|
||||
const [$select, $fakeSelect] = this.selectActions[button as GamepadKey]!;
|
||||
$select.value = actions.mapping[button as GamepadKey] || '';
|
||||
$select.disabled = isDefaultPreset;
|
||||
$fakeSelect && ($fakeSelect.disabled = isDefaultPreset);
|
||||
|
||||
BxEvent.dispatch($select, 'input', {
|
||||
ignoreOnChange: true,
|
||||
manualTrigger: true,
|
||||
});
|
||||
}
|
||||
|
||||
super.updateButtonStates();
|
||||
}
|
||||
|
||||
private updatePreset() {
|
||||
const newData: ControllerShortcutPresetData = deepClone(this.BLANK_PRESET_DATA);
|
||||
|
||||
let button: unknown;
|
||||
for (button in this.selectActions) {
|
||||
const [$select, _] = this.selectActions[button as GamepadKey]!;
|
||||
|
||||
const action = $select.value;
|
||||
if (!action) {
|
||||
continue;
|
||||
}
|
||||
|
||||
newData.mapping[button as GamepadKey] = action as ShortcutAction;
|
||||
}
|
||||
|
||||
const preset = this.allPresets.data[this.currentPresetId];
|
||||
preset.data = newData;
|
||||
this.presetsDb.updatePreset(preset);
|
||||
|
||||
StreamSettings.refreshControllerSettings();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user