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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Format User Controls gamepad profiles and clarify editable defaults -… · ToolboxAid/HTML-JavaScript-Gaming@89ca79d · GitHub
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+
functionphysicalInputSupportsTuning(physicalInput){
100+
returnphysicalInputIsAnalog(physicalInput)||Boolean(physicalInputSensitivityDescriptor(physicalInput));
101+
}
102+
99103
functioncreateSliderControl({ ariaLabel, dataName, defaultValue, index, max, min, step, unit, value }){
100104
constinput=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-
constwrapper=document.createElement("div");
498-
wrapper.className="content-grid";
499-
wrapper.dataset.accountUserControlsInputPair="true";
499+
constrow=document.createElement("tr");
500+
row.dataset.accountUserControlsInputPair="true";
500501
consteditablePhysicalInput=profile.deviceType==="Keyboard"||profile.deviceType==="Mouse";
501502
constphysicalInputControl=editablePhysicalInput
502503
? document.createElement("input")
503504
: document.createElement("strong");
505+
constphysicalInputCell=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
conststack=document.createElement("div");
513516
stack.className="content-stack content-stack--compact";
514517
constnormalizedOptions=[
@@ -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+
constvalidation=document.createElement("p");
545+
validation.className="status";
546+
validation.dataset.accountUserControlsInputValidation=String(index);
547+
stack.append(validation);
548+
549+
constdeadzoneCell=document.createElement("td");
550+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
542551
constdeadzone=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+
constinvertCell=document.createElement("td");
564+
if(physicalInputSupportsTuning(inputMapping.physicalInput)){
549565
constinvert=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+
constsensitivityCell=document.createElement("td");
555575
constsensitivity=physicalInputSensitivityDescriptor(inputMapping.physicalInput);
556576
if(sensitivity){
557577
constvalue=Number.isFinite(Number(inputMapping.sensitivity))
558578
? Number(inputMapping.sensitivity)
559579
: sensitivity.defaultValue;
560-
constslider=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-
constvalidation=document.createElement("p");
574-
validation.className="status";
575-
validation.dataset.accountUserControlsInputValidation=String(index);
576-
stack.append(validation);
577-
wrapper.append(physicalInputControl,stack);
578-
returnwrapper;
594+
595+
row.append(physicalInputCell,controlCell(stack),deadzoneCell,invertCell,sensitivityCell);
596+
returnrow;
579597
}
580598

581599
renderEditingRows(values={}){
582600
constprofile=this.normalizeProfile(values);
583601
constrow=document.createElement("tr");
584602
row.dataset.accountUserControlsEditingRow="true";
603+
constcontrollerName=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+
constcontrollerCell=document.createElement("td");
609+
constcontrollerStack=document.createElement("div");
610+
controllerStack.className="content-stack content-stack--compact";
611+
constdeviceType=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
constactions=document.createElement("td");
586617
constgroup=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
constdetailsCell=document.createElement("td");
606637
detailsCell.colSpan=7;
607-
constgrid=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+
constwrapper=document.createElement("div");
639+
wrapper.className="table-wrapper";
640+
consttable=document.createElement("table");
641+
table.className="data-table";
642+
table.dataset.accountUserControlsGeneratedInputTable="true";
643+
table.setAttribute("aria-label",`${profile.controllerName} generated controller inputs`);
644+
consthead=document.createElement("thead");
645+
constheadRow=document.createElement("tr");
646+
["Physical Input","Normalized Control","Deadzone","Invert","Sensitivity"].forEach((heading)=>{
647+
constcell=document.createElement("th");
648+
cell.textContent=heading;
649+
headRow.append(cell);
650+
});
651+
head.append(headRow);
652+
constbody=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
constvalues=this.editingProfile?.values||{};
652698
constdetails=this.root.querySelector("[data-account-user-controls-editing-details]");
699+
constcontrollerNameInput=this.root.querySelector("[data-account-user-controls-controller-name]");
700+
constpreviousControllerName=normalizeText(values.controllerName);
701+
constcontrollerName=normalizeText(controllerNameInput?.value??previousControllerName)
702+
||previousControllerName
703+
||normalizeText(values.deviceType)
704+
||"Game Controller";
705+
constpreviousProfileName=normalizeText(values.mappingProfile||values.profileName);
706+
constmappingProfile=previousProfileName===`${previousControllerName} Profile`
707+
? `${controllerName} Profile`
708+
: previousProfileName||`${controllerName} Profile`;
653709
constinputMappings=(values.inputMappings||[]).map((mapping,index)=>{
654710
constphysicalInputControl=details?.querySelector(`[data-account-user-controls-physical-input="${index}"]`);
655711
constnormalizedSelect=details?.querySelector(`[data-account-user-controls-input-normalized="${index}"]`);
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729
});
674730
returnthis.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
consttarget=event.targetinstanceofElement ? 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
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Keyboard">
3535
<summary>Keyboard</summary>
3636
<divclass="accordion-body content-stack">
37-
<pclass="status">Keyboard defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
37+
<pclass="status">Default profile in use. Create my profile to save your own keyboard mappings.</p>
3838
<divclass="table-wrapper">
3939
<tableclass="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
<divclass="content-cluster" aria-label="Keyboard user controls">
51-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Edit Keyboard Mappings</button>
51+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Keyboard">Create my profile</button>
5252
</div>
5353
<divclass="table-wrapper">
5454
<tableclass="data-table" aria-label="Keyboard user control profile" data-account-user-controls-table="Keyboard">
@@ -71,7 +71,7 @@ <h2>Physical Input Mapping</h2>
7171
<detailsclass="vertical-accordion" opendata-account-user-controls-section="Mouse">
7272
<summary>Mouse</summary>
7373
<divclass="accordion-body content-stack">
74-
<pclass="status">Mouse defaults are visible fallbacks. They are not saved as user-created profiles until you create and save a profile.</p>
74+
<pclass="status">Default profile in use. Create my profile to save your own mouse mappings.</p>
7575
<divclass="table-wrapper">
7676
<tableclass="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
<divclass="content-cluster" aria-label="Mouse user controls">
88-
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Edit Mouse Mappings</button>
88+
<buttonclass="btn" type="button" data-account-user-controls-edit-family="Mouse">Create my profile</button>
8989
</div>
9090
<divclass="table-wrapper">
9191
<tableclass="data-table" aria-label="Mouse user control profile" data-account-user-controls-table="Mouse">
@@ -115,7 +115,6 @@ <h2>Physical Input Mapping</h2>
115115
<selectdata-account-user-controls-device></select>
116116
</label>
117117
<buttonclass="btn" type="button" data-account-user-controls-add-profile>Create User Control Profile</button>
118-
<buttonclass="btn primary" type="button" data-account-user-controls-save-all>Save</button>
119118
</div>
120119
<pclass="status" role="status" data-account-user-controls-device-status>Game controllers auto-detect after the browser exposes them.</p>
121120
<divclass="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)