Parcourir la source

Fixing input bindings

Edgar il y a 1 mois
Parent
commit
5409ebc227
5 fichiers modifiés avec 41 ajouts et 29 suppressions
  1. 3 3
      OpenPuck/config.cpp
  2. 1 1
      OpenPuck/config.h
  3. 22 11
      OpenPuck/mode_switch2_pro.cpp
  4. 8 7
      OpenPuck/webusb_config.cpp
  5. 7 7
      docs/index.html

+ 3 - 3
OpenPuck/config.cpp

@@ -117,9 +117,9 @@ struct Cfg {
 // tail field treats as "unset" and replaces with its default.
 #define CFG_LEN_MIN (offsetof(struct Cfg, chordDpad))
 
-static uint8_t g_cfgExt[CFG_EXT_STORAGE_BYTES] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
+static uint8_t g_cfgExt[CFG_EXT_STORAGE_BYTES] = { 0xFF, 0xFF, 0xFF, 0xFF,
+						   0xFF, 0xFF, 0xFF, 0xFF,
+						   0xFF, 0xFF, 0xFF };
 
 uint8_t cfgExtRead(uint8_t index)
 {

+ 1 - 1
OpenPuck/config.h

@@ -231,7 +231,7 @@ extern uint16_t g_loopPeriodUs;
 extern uint8_t g_loopWorst;
 extern uint16_t g_loopWorstUs;
 
-#define CFG_EXT_STORAGE_BYTES 10u
+#define CFG_EXT_STORAGE_BYTES 11u
 uint8_t cfgExtRead(uint8_t index);
 void cfgExtWrite(uint8_t index, uint8_t value);
 

+ 22 - 11
OpenPuck/mode_switch2_pro.cpp

@@ -78,7 +78,7 @@ static volatile uint32_t g_sw2Counter32 = 0;
 static int8_t g_sw2LastRumbleBond = -1;
 static uint16_t g_sw2LastRumbleLeft = 0;
 static uint16_t g_sw2LastRumbleRight = 0;
-static uint8_t g_sw2Map[7] = { 9, 10, 23, 22, 18, 11, 21 };
+static uint8_t g_sw2Map[8] = { 19, 20, 23, 22, 9, 10, 11, 18 };
 static bool g_sw2MapLoaded = false;
 
 static void switch2ProLoadMap()
@@ -86,9 +86,15 @@ static void switch2ProLoadMap()
 	if (g_sw2MapLoaded)
 		return;
 	g_sw2MapLoaded = true;
-	static const uint8_t def[7] = { 9, 10, 23, 22, 18, 11, 21 };
+	static const uint8_t legacyDef[7] = { 9, 10, 23, 22, 18, 11, 21 };
+	static const uint8_t def[8] = { 19, 20, 23, 22, 9, 10, 11, 18 };
+	const bool qamMissing = cfgExtRead(10u) == 0xffu;
+	bool migrateLegacyDefaults = qamMissing;
+	for (uint8_t i = 0; i < 7 && migrateLegacyDefaults; i++)
+		migrateLegacyDefaults = cfgExtRead((uint8_t)(3u + i)) ==
+					legacyDef[i];
 	bool normalize = false;
-	for (uint8_t i = 0; i < 7; i++) {
+	for (uint8_t i = 0; i < 8; i++) {
 		const uint8_t saved = cfgExtRead((uint8_t)(3u + i));
 		if (saved <= 23u) {
 			g_sw2Map[i] = saved;
@@ -98,6 +104,13 @@ static void switch2ProLoadMap()
 			normalize = true;
 		}
 	}
+	if (migrateLegacyDefaults) {
+		for (uint8_t i = 0; i < 7; i++) {
+			g_sw2Map[i] = def[i];
+			cfgExtWrite((uint8_t)(3u + i), def[i]);
+		}
+		normalize = true;
+	}
 	if (normalize)
 		saveCfg();
 }
@@ -105,13 +118,13 @@ static void switch2ProLoadMap()
 uint8_t switch2ProMapGet(uint8_t index)
 {
 	switch2ProLoadMap();
-	return index < 7u ? g_sw2Map[index] : 0u;
+	return index < 8u ? g_sw2Map[index] : 0u;
 }
 
 void switch2ProMapSet(uint8_t index, uint8_t value)
 {
 	switch2ProLoadMap();
-	if (index >= 7u || value > 23u)
+	if (index >= 8u || value > 23u)
 		return;
 	g_sw2Map[index] = value;
 	cfgExtWrite((uint8_t)(3u + index), value);
@@ -291,7 +304,6 @@ static void sw2Buttons(uint8_t slot, uint8_t b09[3], uint8_t b05[4])
 	memset(b09, 0, 3);
 	memset(b05, 0, 4);
 	uint32_t b = g_in[slot].buttons;
-	bool qam = g_qamMap && (b & TB_QAM);
 	if ((b & CHORD_BACK4) == CHORD_BACK4)
 		b &= ~(uint32_t)(TB_A | TB_B | TB_X | TB_Y | TB_DUP | TB_DDN |
 				 TB_DLF | TB_DRT);
@@ -324,13 +336,12 @@ static void sw2Buttons(uint8_t slot, uint8_t b09[3], uint8_t b05[4])
 	if (b & TB_DRT)
 		sw2SetCode(15, b09, b05);
 
-	static const uint32_t source[7] = { TB_L4,   TB_R4,   TB_L5,   TB_R5,
-					    TB_VIEW, TB_MENU, TB_STEAM };
-	for (uint8_t i = 0; i < 7; i++)
+	static const uint32_t source[8] = {
+		TB_L4, TB_R4, TB_L5, TB_R5, TB_VIEW, TB_MENU, TB_STEAM, TB_QAM
+	};
+	for (uint8_t i = 0; i < 8; i++)
 		if (b & source[i])
 			sw2SetCode(switch2ProMapGet(i), b09, b05);
-	if (qam)
-		sw2SetCode(g_qamMap, b09, b05);
 }
 
 static uint8_t sw2PowerInfo(uint8_t slot)

+ 8 - 7
OpenPuck/webusb_config.cpp

@@ -106,8 +106,8 @@ static bool boardCommand(uint8_t op)
 //                [v20: p[187..194] per-type trackpad->stick map, 4x2B {left pad, right pad} (PS_OFF/LEFT/RIGHT)]
 //                [v21: p[53] rumble strength as PERCENT/2 (field 22, revived); p[195] rumble style
 //                 (field 39, RUMBLE_STYLE_* in haptics.h)]
-//                p[196..202]: Switch 2 Pro L4/R4/L5/R5/View/Menu/Steam targets (fields 90..96)
-#define WB_PAYLEN 201
+//                p[196..203]: Switch 2 Pro L4/R4/L5/R5/View/Menu/Steam/QAM targets (fields 90..97)
+#define WB_PAYLEN 202
 // The blob send is drop-on-full (never blocks loop), so the vendor TX FIFO MUST be able to hold a whole blob
 // -- otherwise tud_vendor_write_available() never reaches the frame size and EVERY frame is dropped (blank
 // panel / stale mappings). The Makefile sets -DCFG_TUD_VENDOR_TX_BUFSIZE=256; guard it here so a build without
@@ -132,7 +132,7 @@ static void webusbSendBlob()
 	p[0] = 0xA5;
 	p[1] = WB_PAYLEN;
 
-	// Switch 2 Pro mappings use fields 90..96 and blob bytes p[196..202].
+	// Switch 2 Pro mappings use fields 90..97 and blob bytes p[196..203].
 	// protocol version (21 = +rumble style (field 39, blob p[195]) and the REVIVED rumble-strength field 22
 	// at blob p[53], now carrying percent/2; 20 = +per-type trackpad->stick mapping (fields 80..87, blob
 	// p[187..194]); 19 = +Switch Pro legacy-gyro select (field 38, blob p[186]); the Switch report-rate and
@@ -143,7 +143,7 @@ static void webusbSendBlob()
 	// unknown op; 15 = +staged firmware-update ops 0x20..0x24; 14 = +landAll87 toggle; 13 = +per-slot link
 	// stats; 12 = +relay rate + clock fingerprint; 11 = +reset cause; 10 = +ledBright per type; 9 = +per-type
 	// cfg; 8 = +per-slot link status; 7 = +raw accel; 6 = +swPro120/gyroScale)
-	p[2] = 22;
+	p[2] = 23;
 	p[3] = g_usbMode;
 	p[4] = (uint8_t)g_mDiv;
 	p[5] = (uint8_t)g_mFric;
@@ -325,9 +325,9 @@ static void webusbSendBlob()
 		p[187 + et * 2] = g_padStickCfg[et][0];
 		p[188 + et * 2] = g_padStickCfg[et][1];
 	}
-	// Switch 2 Pro keeps these seven source mappings separate from
-	// generic ET_SWITCH so GL/GR/C edits cannot alter Switch Pro/HORI.
-	for (int i = 0; i < 7; i++)
+	// Switch 2 Pro keeps these eight source mappings separate from
+	// generic ET_SWITCH so GL/GR/C/QAM edits cannot alter Switch Pro/HORI.
+	for (int i = 0; i < 8; i++)
 		p[196 + i] = switch2ProMapGet((uint8_t)i);
 	// CRITICAL: usb_web.write() SPINS (`while (remain && _connected) yield();`) until the IN FIFO drains or the
 	// panel disconnects. If the panel holds the WebUSB interface open but stops reading its IN endpoint -- a
@@ -1054,6 +1054,7 @@ void webusbPoll()
 				case 94:
 				case 95:
 				case 96:
+				case 97:
 					switch2ProMapSet((uint8_t)(f - 90), v);
 					break;
 

+ 7 - 7
docs/index.html

@@ -589,7 +589,7 @@ const TYPE_DEFS = [
   {key:"DS5", name:"DS5", labels:{1:"Cross",2:"Circle",3:"Square",4:"Triangle",5:"L1",6:"R1",7:"L3",8:"R3",9:"Create",10:"Options",11:"PS",19:"L2",20:"R2",...DPAD,16:"Touchpad Click",17:"Mute"}},
 ];
 // Which emulated type a USB mode belongs to (mirror of firmware etypeForMode); -1 = puck mode (no type).
-const SW2_SOURCE_NAMES = ["L4 (back upper-left)","R4 (back upper-right)","L5 (back lower-left)","R5 (back lower-right)","View","Menu","Steam"];
+const SW2_SOURCE_NAMES = ["L4 (back upper-left)","R4 (back upper-right)","L5 (back lower-left)","R5 (back lower-right)","View","Menu","Steam","QAM (3 dots)"];
 const SW2_TARGETS = [[1,"A"],[2,"B"],[3,"X"],[4,"Y"],[5,"L"],[6,"R"],[7,"L-Stick"],[8,"R-Stick"],[9,"Minus"],[10,"Plus"],[11,"Home"],[12,"D-pad Up"],[13,"D-pad Down"],[14,"D-pad Left"],[15,"D-pad Right"],[18,"Capture"],[19,"ZL"],[20,"ZR"],[21,"C"],[22,"GR"],[23,"GL"]];
 const sw2MapEls=[];
 (function buildSw2Map(){
@@ -961,9 +961,9 @@ function applyBlob(p){
   const rumbleScale=rumbleCap?p[51]*2:200, rumbleStyle=rumbleCap?p[193]:0;
   const rssi=(p.length>37?p[37]:0);
 
-  // Seven Switch 2 Pro physical-source mappings occupy payload p[194..200].
-  const sw2MapCap=(p[0]>=22 && p.length>200);
-  const sw2Map=sw2MapCap?p.slice(194,201):[9,10,23,22,18,11,21];
+  // Eight Switch 2 Pro physical-source mappings occupy payload p[194..201].
+  const sw2MapCap=(p[0]>=23 && p.length>201);
+  const sw2Map=sw2MapCap?p.slice(194,202):[19,20,23,22,9,10,11,18];
   // per-slot link status (protocol v8, p.length >= 73)
   const hasSlotsData = p.length >= 73;
   if (hasSlotsData) {
@@ -1301,7 +1301,7 @@ function buildBackup(p, bp){
   // map snapshot would be empty, which would incorrectly clear bindings on restore.
   if(lizardLoaded && lizardCapable() && !lizardBusy)
     cfg.lizardMap=lizardBindings.map(b=>({outType:b.outType,od:b.od.slice(),trig:b.trig>>>0,hold:b.hold>>>0}));
-  if(p[0]>=22 && p.length>200) cfg.sw2Map=Array.from(p.slice(194,201));
+  if(p[0]>=23 && p.length>201) cfg.sw2Map=Array.from(p.slice(194,202));
   return { magic:"openpuck-backup", version:(cfg.lizardMap?2:1), bonds, config:cfg };
 }
 function downloadBackup(obj){
@@ -1347,7 +1347,7 @@ async function importBackup(file){
   // slots, and the final commit.
   const typeN=Array.isArray(c.types)?Math.min(c.types.length,4):0;
   const lizardN=(Array.isArray(c.lizardMap) && lizardCapable())?Math.min(c.lizardMap.length,LZ_MAX):0;
-  const baseN=6 + (Array.isArray(c.chordD)?4:0) + (c.swGyroLegacy!==undefined?1:0) + (Array.isArray(c.sw2Map)?7:0);
+  const baseN=6 + (Array.isArray(c.chordD)?4:0) + (c.swGyroLegacy!==undefined?1:0) + (Array.isArray(c.sw2Map)?Math.min(c.sw2Map.length,8):0);
   const padStickN=Array.isArray(c.types)?c.types.slice(0,typeN).filter(t=>Array.isArray(t.padStick)).length*2:0;
   const total=baseN + typeN*9 + padStickN + lizardN + 4 + 1;
   let step=0, stage="";
@@ -1378,7 +1378,7 @@ async function importBackup(file){
     // Switch Pro gyro mapping (v19+ backups only). Backups also carry rumble/swProRate/swGyro10 from the
     // removed settings; those fields no longer exist on the puck, so they are not replayed.
     if(c.swGyroLegacy!==undefined) await sf(38, c.swGyroLegacy?1:0);
-    if(Array.isArray(c.sw2Map)) for(let i=0;i<7;i++) await sf(90+i, c.sw2Map[i]);
+    if(Array.isArray(c.sw2Map)) for(let i=0;i<Math.min(c.sw2Map.length,8);i++) await sf(90+i, c.sw2Map[i]);
     // c.types is absent in some very old backups created before per-type paddle/haptic config
     // was added to the panel export; guard so a missing field never crashes the import mid-flight.
     if(typeN){