@@ -96,6 +96,10 @@ function rangeValueLabel(value, unit = "") {
9696return `${ value } ${ unit } ` ;
9797}
9898
99+ function physicalInputSupportsTuning ( physicalInput ) {
100+ return physicalInputIsAnalog ( physicalInput ) || Boolean ( physicalInputSensitivityDescriptor ( physicalInput ) ) ;
101+ }
102+
99103function createSliderControl ( { ariaLabel, dataName, defaultValue, index, max, min, step, unit, value } ) {
100104const input = document . createElement ( "input" ) ;
101105input . type = "range" ;
@@ -133,7 +137,6 @@ export class AccountUserControlsPage {
133137familyButtons : [ ...root . querySelectorAll ( "[data-account-user-controls-edit-family]" ) ] ,
134138lists : [ ...root . querySelectorAll ( "[data-account-user-controls-list]" ) ] ,
135139refresh : root . querySelector ( "[data-account-user-controls-refresh]" ) ,
136- saveAll : root . querySelector ( "[data-account-user-controls-save-all]" ) ,
137140status : root . querySelector ( "[data-account-user-controls-status]" ) ,
138141types : root . querySelector ( "[data-account-user-controls-types]" ) ,
139142} ;
@@ -151,7 +154,6 @@ export class AccountUserControlsPage {
151154this . setStatus ( this . deviceRefreshMessage ( ) ) ;
152155} ) ;
153156this . elements . addProfile ?. addEventListener ( "click" , ( ) => this . addProfileForSelectedDevice ( ) ) ;
154- this . elements . saveAll ?. addEventListener ( "click" , ( ) => this . saveCurrentState ( ) ) ;
155157this . elements . deviceSelect ?. addEventListener ( "change" , ( ) => this . renderDeviceStatus ( ) ) ;
156158this . elements . familyButtons . forEach ( ( button ) => {
157159button . addEventListener ( "click" , ( ) => this . editFamilyMappings ( button . dataset . accountUserControlsEditFamily || "" ) ) ;
@@ -344,7 +346,7 @@ export class AccountUserControlsPage {
344346row . append (
345347tableCell ( mapping . physicalInput ) ,
346348tableCell ( mapping . normalizedInput || mapping . positiveNormalizedInput || mapping . negativeNormalizedInput || "Unassigned" ) ,
347- tableCell ( "Visible fallback " ) ,
349+ tableCell ( "Default profile in use " ) ,
348350) ;
349351rowsByFamily . get ( family ) ?. push ( row ) ;
350352} ) ;
@@ -494,13 +496,13 @@ export class AccountUserControlsPage {
494496}
495497
496498inputControl ( profile , inputMapping , index ) {
497- const wrapper = document . createElement ( "div" ) ;
498- wrapper . className = "content-grid" ;
499- wrapper . dataset . accountUserControlsInputPair = "true" ;
499+ const row = document . createElement ( "tr" ) ;
500+ row . dataset . accountUserControlsInputPair = "true" ;
500501const editablePhysicalInput = profile . deviceType === "Keyboard" || profile . deviceType === "Mouse" ;
501502const physicalInputControl = editablePhysicalInput
502503 ? document . createElement ( "input" )
503504 : document . createElement ( "strong" ) ;
505+ const physicalInputCell = document . createElement ( "td" ) ;
504506if ( editablePhysicalInput ) {
505507physicalInputControl . type = "text" ;
506508physicalInputControl . value = inputMapping . physicalInput ;
@@ -509,6 +511,7 @@ export class AccountUserControlsPage {
509511} else {
510512physicalInputControl . textContent = inputMapping . physicalInput ;
511513}
514+ physicalInputCell . append ( physicalInputControl ) ;
512515const stack = document . createElement ( "div" ) ;
513516stack . className = "content-stack content-stack--compact" ;
514517const normalizedOptions = [
@@ -538,26 +541,43 @@ export class AccountUserControlsPage {
538541select . dataset . accountUserControlsInputNormalized = String ( index ) ;
539542stack . append ( select ) ;
540543}
541- if ( physicalInputIsAnalog ( inputMapping . physicalInput ) || normalizedInputIsAnalog ( inputMapping . normalizedInput ) ) {
544+ const validation = document . createElement ( "p" ) ;
545+ validation . className = "status" ;
546+ validation . dataset . accountUserControlsInputValidation = String ( index ) ;
547+ stack . append ( validation ) ;
548+
549+ const deadzoneCell = document . createElement ( "td" ) ;
550+ if ( physicalInputSupportsTuning ( inputMapping . physicalInput ) ) {
542551const deadzone = document . createElement ( "input" ) ;
543552deadzone . type = "number" ;
544553deadzone . min = "0" ;
545554deadzone . max = "1" ;
546555deadzone . step = "0.05" ;
547556deadzone . value = String ( inputMapping . deadzone ) ;
548557deadzone . dataset . accountUserControlsDeadzone = String ( index ) ;
558+ deadzoneCell . append ( deadzone ) ;
559+ } else {
560+ deadzoneCell . textContent = "Not applicable" ;
561+ }
562+
563+ const invertCell = document . createElement ( "td" ) ;
564+ if ( physicalInputSupportsTuning ( inputMapping . physicalInput ) ) {
549565const invert = document . createElement ( "input" ) ;
550566invert . type = "checkbox" ;
551567invert . checked = Boolean ( inputMapping . invert ) ;
552568invert . dataset . accountUserControlsInvert = String ( index ) ;
553- stack . append ( labeledControl ( "Deadzone" , deadzone ) , labeledControl ( "Invert" , invert ) ) ;
569+ invertCell . append ( invert ) ;
570+ } else {
571+ invertCell . textContent = "Not applicable" ;
554572}
573+
574+ const sensitivityCell = document . createElement ( "td" ) ;
555575const sensitivity = physicalInputSensitivityDescriptor ( inputMapping . physicalInput ) ;
556576if ( sensitivity ) {
557577const value = Number . isFinite ( Number ( inputMapping . sensitivity ) )
558578 ? Number ( inputMapping . sensitivity )
559579 : sensitivity . defaultValue ;
560- const slider = createSliderControl ( {
580+ sensitivityCell . append ( createSliderControl ( {
561581ariaLabel : sensitivity . label ,
562582dataName : "accountUserControlsSensitivity" ,
563583defaultValue : sensitivity . defaultValue ,
@@ -567,21 +587,32 @@ export class AccountUserControlsPage {
567587step : sensitivity . step ,
568588unit : sensitivity . unit ,
569589 value,
570- } ) ;
571- stack . append ( labeledControl ( sensitivity . label , slider ) ) ;
590+ } ) ) ;
591+ } else {
592+ sensitivityCell . textContent = "Not applicable" ;
572593}
573- const validation = document . createElement ( "p" ) ;
574- validation . className = "status" ;
575- validation . dataset . accountUserControlsInputValidation = String ( index ) ;
576- stack . append ( validation ) ;
577- wrapper . append ( physicalInputControl , stack ) ;
578- return wrapper ;
594+
595+ row . append ( physicalInputCell , controlCell ( stack ) , deadzoneCell , invertCell , sensitivityCell ) ;
596+ return row ;
579597}
580598
581599renderEditingRows ( values = { } ) {
582600const profile = this . normalizeProfile ( values ) ;
583601const row = document . createElement ( "tr" ) ;
584602row . dataset . accountUserControlsEditingRow = "true" ;
603+ const controllerName = document . createElement ( "input" ) ;
604+ controllerName . type = "text" ;
605+ controllerName . value = profile . controllerName ;
606+ controllerName . dataset . accountUserControlsControllerName = "true" ;
607+ controllerName . setAttribute ( "aria-label" , "Physical Controller name" ) ;
608+ const controllerCell = document . createElement ( "td" ) ;
609+ const controllerStack = document . createElement ( "div" ) ;
610+ controllerStack . className = "content-stack content-stack--compact" ;
611+ const deviceType = document . createElement ( "span" ) ;
612+ deviceType . className = "status" ;
613+ deviceType . textContent = profile . deviceType ;
614+ controllerStack . append ( deviceType , labeledControl ( "Physical Controller" , controllerName ) ) ;
615+ controllerCell . append ( controllerStack ) ;
585616const actions = document . createElement ( "td" ) ;
586617const group = document . createElement ( "div" ) ;
587618group . className = "action-group action-group--tight" ;
@@ -591,7 +622,7 @@ export class AccountUserControlsPage {
591622) ;
592623actions . append ( group ) ;
593624row . append (
594- tableCell ( ` ${ profile . deviceType } : ${ profile . controllerName } ` ) ,
625+ controllerCell ,
595626tableCell ( `${ profile . inputMappings . length } Physical Inputs` ) ,
596627tableCell ( this . profileInputSummary ( profile ) ) ,
597628tableCell ( this . profileAnalogSummary ( profile ) ) ,
@@ -604,10 +635,25 @@ export class AccountUserControlsPage {
604635detailsRow . dataset . accountUserControlsEditingDetails = "true" ;
605636const detailsCell = document . createElement ( "td" ) ;
606637detailsCell . colSpan = 7 ;
607- const grid = document . createElement ( "div" ) ;
608- grid . className = "content-grid content-grid--three" ;
609- grid . append ( ...profile . inputMappings . map ( ( inputMapping , index ) => this . inputControl ( profile , inputMapping , index ) ) ) ;
610- detailsCell . append ( grid ) ;
638+ const wrapper = document . createElement ( "div" ) ;
639+ wrapper . className = "table-wrapper" ;
640+ const table = document . createElement ( "table" ) ;
641+ table . className = "data-table" ;
642+ table . dataset . accountUserControlsGeneratedInputTable = "true" ;
643+ table . setAttribute ( "aria-label" , `${ profile . controllerName } generated controller inputs` ) ;
644+ const head = document . createElement ( "thead" ) ;
645+ const headRow = document . createElement ( "tr" ) ;
646+ [ "Physical Input" , "Normalized Control" , "Deadzone" , "Invert" , "Sensitivity" ] . forEach ( ( heading ) => {
647+ const cell = document . createElement ( "th" ) ;
648+ cell . textContent = heading ;
649+ headRow . append ( cell ) ;
650+ } ) ;
651+ head . append ( headRow ) ;
652+ const body = document . createElement ( "tbody" ) ;
653+ body . append ( ...profile . inputMappings . map ( ( inputMapping , index ) => this . inputControl ( profile , inputMapping , index ) ) ) ;
654+ table . append ( head , body ) ;
655+ wrapper . append ( table ) ;
656+ detailsCell . append ( wrapper ) ;
611657detailsRow . append ( detailsCell ) ;
612658return [ row , detailsRow ] ;
613659}
@@ -650,6 +696,16 @@ export class AccountUserControlsPage {
650696profileFromEditingRow ( ) {
651697const values = this . editingProfile ?. values || { } ;
652698const details = this . root . querySelector ( "[data-account-user-controls-editing-details]" ) ;
699+ const controllerNameInput = this . root . querySelector ( "[data-account-user-controls-controller-name]" ) ;
700+ const previousControllerName = normalizeText ( values . controllerName ) ;
701+ const controllerName = normalizeText ( controllerNameInput ?. value ?? previousControllerName )
702+ || previousControllerName
703+ || normalizeText ( values . deviceType )
704+ || "Game Controller" ;
705+ const previousProfileName = normalizeText ( values . mappingProfile || values . profileName ) ;
706+ const mappingProfile = previousProfileName === `${ previousControllerName } Profile`
707+ ? `${ controllerName } Profile`
708+ : previousProfileName || `${ controllerName } Profile` ;
653709const inputMappings = ( values . inputMappings || [ ] ) . map ( ( mapping , index ) => {
654710const physicalInputControl = details ?. querySelector ( `[data-account-user-controls-physical-input="${ index } "]` ) ;
655711const normalizedSelect = details ?. querySelector ( `[data-account-user-controls-input-normalized="${ index } "]` ) ;
@@ -673,9 +729,11 @@ export class AccountUserControlsPage {
673729} ) ;
674730return this . normalizeProfile ( {
675731 ...values ,
732+ controllerName,
676733id : this . editingProfile ?. id || "" ,
677734 inputMappings,
678735inputs : inputMappings . map ( ( mapping ) => mapping . physicalInput ) ,
736+ mappingProfile,
679737} ) ;
680738}
681739
@@ -761,23 +819,6 @@ export class AccountUserControlsPage {
761819this . 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-
781822handleListClick ( event ) {
782823const target = event . target instanceof Element ? event . target . closest ( "button" ) : null ;
783824if ( ! target ) {
0 commit comments