|
|
@@ -121,7 +121,8 @@
|
|
|
<div class="row"><label>R4 (back upper-right)</label><select class="back" data-i="1"></select></div>
|
|
|
<div class="row"><label>L5 (back lower-left)</label><select class="back" data-i="2"></select></div>
|
|
|
<div class="row"><label>R5 (back lower-right)</label><select class="back" data-i="3"></select></div>
|
|
|
- <p class="note">Back-paddle → button, applied in Xbox & Switch modes.</p>
|
|
|
+ <div class="row"><label>QAM (3 dots)</label><select id="qamMap"></select></div>
|
|
|
+ <p class="note">Back-paddle → button, applied in Xbox & Switch modes. QAM remap applies to all modes (0 = default per-mode behavior).</p>
|
|
|
</div>
|
|
|
|
|
|
<div class="card logonly">
|
|
|
@@ -152,6 +153,11 @@ function log(m){ const l=$("#log"); l.textContent=(new Date().toLocaleTimeString
|
|
|
for(const sel of document.querySelectorAll("select.back")){
|
|
|
for(const [c,n] of BTN_CODES){ const o=document.createElement("option"); o.value=c; o.textContent=n; sel.appendChild(o); }
|
|
|
}
|
|
|
+// QAM remap dropdown: same codes but with a "Default" entry at 0
|
|
|
+{ const sel = document.getElementById("qamMap");
|
|
|
+ const d = document.createElement("option"); d.value=0; d.textContent="Default (varies by mode)"; sel.appendChild(d);
|
|
|
+ for(const [c,n] of BTN_CODES){ if(c===0) continue; const o=document.createElement("option"); o.value=c; o.textContent=n; sel.appendChild(o); }
|
|
|
+}
|
|
|
for(const sel of document.querySelectorAll("select.chord")){
|
|
|
MODE_NAMES.forEach((n,i)=>{ const o=document.createElement("option"); o.value=i; o.textContent=n; sel.appendChild(o); });
|
|
|
}
|
|
|
@@ -211,7 +217,7 @@ async function readBlob(){
|
|
|
}
|
|
|
function applyBlob(p){
|
|
|
// [ver][mode][mDiv][mFric][rsvd][abSwap][b0..b3][slot][up][f1lo][f1hi][pollU100(unused)][newlo][newhi]
|
|
|
- const mode=p[1], mDiv=p[2], mFric=p[3], abSwap=p[5]; // p[4] reserved (ex-padSmooth)
|
|
|
+ const mode=p[1], mDiv=p[2], mFric=p[3], qamMap=p[4], abSwap=p[5]; // p[4] = QAM remap code (0 = default)
|
|
|
const back=[p[6],p[7],p[8],p[9]], slot=p[10], up=p[11], f1=(p[12]|(p[13]<<8));
|
|
|
const newps=(p.length>16?(p[15]|(p[16]<<8)):0), persistMode=(p.length>22?p[22]:0);
|
|
|
const chord=(p.length>25)?[p[23],p[24],p[25]]:[3,1,2]; // v2 blob: chordBtn after qos/persist
|
|
|
@@ -252,6 +258,7 @@ function applyBlob(p){
|
|
|
$("#abSwap").textContent = abSwap? "on":"off"; $("#abSwap").classList.toggle("active",!!abSwap);
|
|
|
$("#persistMode").textContent = persistMode? "on":"off"; $("#persistMode").classList.toggle("active",!!persistMode);
|
|
|
for(const sel of document.querySelectorAll("select.back")){ if(document.activeElement!==sel) sel.value=back[+sel.dataset.i]; }
|
|
|
+ { const sel=$("#qamMap"); if(document.activeElement!==sel) sel.value=qamMap; }
|
|
|
for(const sel of document.querySelectorAll("select.chord")){ if(document.activeElement!==sel) sel.value=chord[+sel.dataset.i]; }
|
|
|
}
|
|
|
function fmtSlider(id,v){ return ""+v; }
|
|
|
@@ -365,6 +372,7 @@ for(const id of ["mDiv","mFric"]){
|
|
|
for(const sel of document.querySelectorAll("select.back")){
|
|
|
sel.addEventListener("change", ()=>setField(5 + +sel.dataset.i, +sel.value));
|
|
|
}
|
|
|
+$("#qamMap").addEventListener("change", ()=>setField(21, +$("#qamMap").value));
|
|
|
for(const sel of document.querySelectorAll("select.chord")){
|
|
|
sel.addEventListener("change", ()=>setField(CHORD_FIELD[+sel.dataset.i], +sel.value));
|
|
|
}
|