Skip to content

Commit 89ca79d

Browse files
committed
Format User Controls gamepad profiles and clarify editable defaults - PR_26162_043-user-controls-gamepad-table-and-defaults
1 parent cbf9b8a commit 89ca79d

9 files changed

Lines changed: 790 additions & 767 deletions

File tree

account/user-controls-page.js

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ function rangeValueLabel(value, unit = "") {
9696
return `${value}${unit}`;
9797
}
9898

99+
function physicalInputSupportsTuning(physicalInput) {
100+
return physicalInputIsAnalog(physicalInput) || Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
function createSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }) {
100104
const input = document.createElement("input");
101105
input.type = "range";
@@ -133,7 +137,6 @@ export class AccountUserControlsPage {
133137
familyButtons: [...root.querySelectorAll("[data-account-user-controls-edit-family]")],
134138
lists: [...root.querySelectorAll("[data-account-user-controls-list]")],
135139
refresh: root.querySelector("[data-account-user-controls-refresh]"),
136-
saveAll: root.querySelector("[data-account-user-controls-save-all]"),
137140
status: root.querySelector("[data-account-user-controls-status]"),
138141
types: root.querySelector("[data-account-user-controls-types]"),
139142
};
@@ -151,7 +154,6 @@ export class AccountUserControlsPage {
151154
this.setStatus(this.deviceRefreshMessage());
152155
});
153156
this.elements.addProfile?.addEventListener("click", () => this.addProfileForSelectedDevice());
154-
this.elements.saveAll?.addEventListener("click", () => this.saveCurrentState());
155157
this.elements.deviceSelect?.addEventListener("change", () => this.renderDeviceStatus());
156158
this.elements.familyButtons.forEach((button) => {
157159
button.addEventListener("click", () => this.editFamilyMappings(button.dataset.accountUserControlsEditFamily || ""));
@@ -344,7 +346,7 @@ export class AccountUserControlsPage {
344346
row.append(
345347
tableCell(mapping.physicalInput),
346348
tableCell(mapping.normalizedInput || mapping.positiveNormalizedInput || mapping.negativeNormalizedInput || "Unassigned"),
347-
tableCell("Visible fallback"),
349+
tableCell("Default profile in use"),
348350
);
349351
rowsByFamily.get(family)?.push(row);
350352
});
@@ -494,13 +496,13 @@ export class AccountUserControlsPage {
494496
}
495497

496498
inputControl(profile, inputMapping, index) {
497-
const wrapper = document.createElement("div");
498-
wrapper.className = "content-grid";
499-
wrapper.dataset.accountUserControlsInputPair = "true";
499+
const row = document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair = "true";
500501
const editablePhysicalInput = profile.deviceType === "Keyboard" || profile.deviceType === "Mouse";
501502
const physicalInputControl = editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
const physicalInputCell = document.createElement("td");
504506
if (editablePhysicalInput) {
505507
physicalInputControl.type = "text";
506508
physicalInputControl.value = inputMapping.physicalInput;
@@ -509,6 +511,7 @@ export class AccountUserControlsPage {
509511
} else {
510512
physicalInputControl.textContent = inputMapping.physicalInput;
511513
}
514+
physicalInputCell.append(physicalInputControl);
512515
const stack = document.createElement("div");
513516
stack.className = "content-stack content-stack--compact";
514517
const normalizedOptions = [
@@ -538,26 +541,43 @@ export class AccountUserControlsPage {
538541
select.dataset.accountUserControlsInputNormalized = String(index);
539542
stack.append(select);
540543
}
541-
if (physicalInputIsAnalog(inputMapping.physicalInput) || normalizedInputIsAnalog(inputMapping.normalizedInput)) {
544+
const validation = document.createElement("p");
545+
validation.className = "status";
546+
validation.dataset.accountUserControlsInputValidation = String(index);
547+
stack.append(validation);
548+
549+
const deadzoneCell = document.createElement("td");
550+
if (physicalInputSupportsTuning(inputMapping.physicalInput)) {
542551
const deadzone = document.createElement("input");
543552
deadzone.type = "number";
544553
deadzone.min = "0";
545554
deadzone.max = "1";
546555
deadzone.step = "0.05";
547556
deadzone.value = String(inputMapping.deadzone);
548557
deadzone.dataset.accountUserControlsDeadzone = String(index);
558+
deadzoneCell.append(deadzone);
559+
} else {
560+
deadzoneCell.textContent = "Not applicable";
561+
}
562+
563+
const invertCell = document.createElement("td");
564+
if (physicalInputSupportsTuning(inputMapping.physicalInput)) {
549565
const invert = document.createElement("input");
550566
invert.type = "checkbox";
551567
invert.checked = Boolean(inputMapping.invert);
552568
invert.dataset.accountUserControlsInvert = String(index);
553-
stack.append(labeledControl("Deadzone", deadzone), labeledControl("Invert", invert));
569+
invertCell.append(invert);
570+
} else {
571+
invertCell.textContent = "Not applicable";
554572
}
573+
574+
const sensitivityCell = document.createElement("td");
555575
const sensitivity = physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if (sensitivity) {
557577
const value = Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
const slider = createSliderControl({
580+
sensitivityCell.append(createSliderControl({
561581
ariaLabel: sensitivity.label,
562582
dataName: "accountUserControlsSensitivity",
563583
defaultValue: sensitivity.defaultValue,
@@ -567,21 +587,32 @@ export class AccountUserControlsPage {
567587
step: sensitivity.step,
568588
unit: sensitivity.unit,
569589
value,
570-
});
571-
stack.append(labeledControl(sensitivity.label, slider));
590+
}));
591+
} else {
592+
sensitivityCell.textContent = "Not applicable";
572593
}
573-
const validation = document.createElement("p");
574-
validation.className = "status";
575-
validation.dataset.accountUserControlsInputValidation = String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl, stack);
578-
return wrapper;
594+
595+
row.append(physicalInputCell, controlCell(stack), deadzoneCell, invertCell, sensitivityCell);
596+
return row;
579597
}
580598

581599
renderEditingRows(values = {}) {
582600
const profile = this.normalizeProfile(values);
583601
const row = document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow = "true";
603+
const controllerName = document.createElement("input");
604+
controllerName.type = "text";
605+
controllerName.value = profile.controllerName;
606+
controllerName.dataset.accountUserControlsControllerName = "true";
607+
controllerName.setAttribute("aria-label", "Physical Controller name");
608+
const controllerCell = document.createElement("td");
609+
const controllerStack = document.createElement("div");
610+
controllerStack.className = "content-stack content-stack--compact";
611+
const deviceType = document.createElement("span");
612+
deviceType.className = "status";
613+
deviceType.textContent = profile.deviceType;
614+
controllerStack.append(deviceType, labeledControl("Physical Controller", controllerName));
615+
controllerCell.append(controllerStack);
585616
const actions = document.createElement("td");
586617
const group = document.createElement("div");
587618
group.className = "action-group action-group--tight";
@@ -591,7 +622,7 @@ export class AccountUserControlsPage {
591622
);
592623
actions.append(group);
593624
row.append(
594-
tableCell(`${profile.deviceType}: ${profile.controllerName}`),
625+
controllerCell,
595626
tableCell(`${profile.inputMappings.length} Physical Inputs`),
596627
tableCell(this.profileInputSummary(profile)),
597628
tableCell(this.profileAnalogSummary(profile)),
@@ -604,10 +635,25 @@ export class AccountUserControlsPage {
604635
detailsRow.dataset.accountUserControlsEditingDetails = "true";
605636
const detailsCell = document.createElement("td");
606637
detailsCell.colSpan = 7;
607-
const grid = document.createElement("div");
608-
grid.className = "content-grid content-grid--three";
609-
grid.append(...profile.inputMappings.map((inputMapping, index) => this.inputControl(profile, inputMapping, index)));
610-
detailsCell.append(grid);
638+
const wrapper = document.createElement("div");
639+
wrapper.className = "table-wrapper";
640+
const table = document.createElement("table");
641+
table.className = "data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable = "true";
643+
table.setAttribute("aria-label", `${profile.controllerName} generated controller inputs`);
644+
const head = document.createElement("thead");
645+
const headRow = document.createElement("tr");
646+
["Physical Input", "Normalized Control", "Deadzone", "Invert", "Sensitivity"].forEach((heading) => {
647+
const cell = document.createElement("th");
648+
cell.textContent = heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
const body = document.createElement("tbody");
653+
body.append(...profile.inputMappings.map((inputMapping, index) => this.inputControl(profile, inputMapping, index)));
654+
table.append(head, body);
655+
wrapper.append(table);
656+
detailsCell.append(wrapper);
611657
detailsRow.append(detailsCell);
612658
return [row, detailsRow];
613659
}
@@ -650,6 +696,16 @@ export class AccountUserControlsPage {
650696
profileFromEditingRow() {
651697
const values = this.editingProfile?.values || {};
652698
const details = this.root.querySelector("[data-account-user-controls-editing-details]");
699+
const controllerNameInput = this.root.querySelector("[data-account-user-controls-controller-name]");
700+
const previousControllerName = normalizeText(values.controllerName);
701+
const controllerName = normalizeText(controllerNameInput?.value ?? previousControllerName)
702+
|| previousControllerName
703+
|| normalizeText(values.deviceType)
704+
|| "Game Controller";
705+
const previousProfileName = normalizeText(values.mappingProfile || values.profileName);
706+
const mappingProfile = previousProfileName === `${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName || `${controllerName} Profile`;
653709
const inputMappings = (values.inputMappings || []).map((mapping, index) => {
654710
const physicalInputControl = details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
const normalizedSelect = details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
return this.normalizeProfile({
675731
...values,
732+
controllerName,
676733
id: this.editingProfile?.id || "",
677734
inputMappings,
678735
inputs: inputMappings.map((mapping) => mapping.physicalInput),
736+
mappingProfile,
679737
});
680738
}
681739

@@ -761,23 +819,6 @@ export class AccountUserControlsPage {
761819
this.setStatus(`PASS: Saved ${profile.mappingProfile}.`);
762820
}
763821

764-
saveCurrentState() {
765-
if (this.editingProfile) {
766-
this.saveEditingProfile();
767-
return;
768-
}
769-
if (!this.profiles.length) {
770-
this.setStatus("FAIL: Create a user control profile before saving.");
771-
return;
772-
}
773-
if (!this.saveProfiles(this.profiles)) {
774-
this.setStatus("FAIL: Account user controls could not reach the shared DB adapter.");
775-
return;
776-
}
777-
this.renderProfiles();
778-
this.setStatus("PASS: Saved account user controls.");
779-
}
780-
781822
handleListClick(event) {
782823
const target = event.target instanceof Element ? event.target.closest("button") : null;
783824
if (!target) {

account/user-controls.html

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ <h2>Physical Input Mapping</h2>
3434
<details class="vertical-accordion" open data-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<div class="accordion-body content-stack">
37-
<p class="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<p class="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<div class="table-wrapper">
3939
<table class="data-table" aria-label="Default keyboard fallback" data-account-user-controls-defaults="Keyboard">
4040
<thead>
@@ -48,7 +48,7 @@ <h2>Physical Input Mapping</h2>
4848
</table>
4949
</div>
5050
<div class="content-cluster" aria-label="Keyboard user controls">
51-
<button class="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<button class="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<div class="table-wrapper">
5454
<table class="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<details class="vertical-accordion" open data-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<div class="accordion-body content-stack">
74-
<p class="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<p class="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<div class="table-wrapper">
7676
<table class="data-table" aria-label="Default mouse fallback" data-account-user-controls-defaults="Mouse">
7777
<thead>
@@ -85,7 +85,7 @@ <h2>Physical Input Mapping</h2>
8585
</table>
8686
</div>
8787
<div class="content-cluster" aria-label="Mouse user controls">
88-
<button class="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<button class="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<div class="table-wrapper">
9191
<table class="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<select data-account-user-controls-device></select>
116116
</label>
117117
<button class="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<button class="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<p class="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<div class="table-wrapper">

docs_build/dev/reports/codex_changed_files.txt

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,18 @@ M account/user-controls-page.js
33
M account/user-controls.html
44
M docs_build/dev/reports/coverage_changed_js_guardrail.txt
55
M docs_build/dev/reports/playwright_v8_coverage_report.txt
6+
M src/dev-runtime/persistence/tool-repositories/input-mapping-mock-repository.js
67
M tests/playwright/tools/InputMappingV2Tool.spec.mjs
7-
M toolbox/controls/controls.js
8-
M toolbox/controls/index.html
9-
?? docs_build/dev/reports/controls-combo-framework-and-user-control-editing-report.md
8+
?? docs_build/dev/reports/user-controls-gamepad-table-and-defaults-report.md
109

1110
# git ls-files --others --exclude-standard
12-
docs_build/dev/reports/controls-combo-framework-and-user-control-editing-report.md
11+
docs_build/dev/reports/user-controls-gamepad-table-and-defaults-report.md
1312

1413
# git diff --stat
15-
account/user-controls-page.js | 165 +++++++++++++++------
16-
account/user-controls.html | 44 +++++-
17-
.../dev/reports/coverage_changed_js_guardrail.txt | 2 +-
18-
.../dev/reports/playwright_v8_coverage_report.txt | 8 +-
19-
tests/playwright/tools/InputMappingV2Tool.spec.mjs | 106 ++++++++-----
20-
toolbox/controls/controls.js | 41 +++++
21-
toolbox/controls/index.html | 6 +
22-
7 files changed, 276 insertions(+), 96 deletions(-)
14+
account/user-controls-page.js | 119 ++++++++++++++-------
15+
account/user-controls.html | 9 +-
16+
.../dev/reports/coverage_changed_js_guardrail.txt | 2 -
17+
.../dev/reports/playwright_v8_coverage_report.txt | 7 +-
18+
.../input-mapping-mock-repository.js | 24 ++++-
19+
tests/playwright/tools/InputMappingV2Tool.spec.mjs | 61 ++++++++---
20+
6 files changed, 149 insertions(+), 73 deletions(-)

0 commit comments

Comments
 (0)