Quellcode durchsuchen

fix(lizard): drive keyboard+mouse for every connected controller, not just slot 0 (#98)

Jari vor 3 Monaten
Ursprung
Commit
70a80f707d
3 geänderte Dateien mit 71 neuen und 53 gelöschten Zeilen
  1. 56 44
      OpenPuck/mode_lizard.cpp
  2. 7 2
      OpenPuck/mode_lizard.h
  3. 8 7
      OpenPuck/puck_hid.cpp

+ 56 - 44
OpenPuck/mode_lizard.cpp

@@ -2,34 +2,52 @@
 #include "triton.h"
 #include "config.h"
 #include "usb_tx.h"
+#include "bonds.h" // NSLOT
 
-void rfLizard(const uint8_t *r, Adafruit_USBD_HID *mdev,
+// Per-controller lizard state. rfLizard runs once per input report on the report's bond slot, so the glide
+// velocity / sub-pixel carry / button + keyboard edge trackers must be PER SLOT -- shared statics would let
+// one controller's motion clobber another's (garbage deltas). Zero-init (static storage) matches the old
+// per-function initial values (all 0 / false).
+struct LizardState {
+	int prx, pry; // last right-pad sample (mouse)
+	bool prt; // right pad was touched last frame
+	float vx, vy, rmx, rmy; // mouse velocity + sub-pixel carry
+	int ply; // last left-pad Y (scroll)
+	bool plt; // left pad was touched last frame
+	float sacc; // scroll accumulator
+	uint8_t pmbtn; // last mouse-button mask
+	bool prevL5, prevR5; // MODE_LIZARD media-key edges (L5/R5)
+	uint8_t pmod, pkc[6]; // last keyboard modifier + keycodes (edge-send)
+};
+static LizardState g_lz[NSLOT];
+
+void rfLizard(int slot, const uint8_t *r, Adafruit_USBD_HID *mdev,
 	      Adafruit_USBD_HID *kdev, uint8_t mrid, uint8_t krid)
 {
+	if (slot < 0 || slot >= NSLOT)
+		return;
+	LizardState &ls = g_lz[slot];
 	uint32_t b = btnsOf(r);
 	bool qamHeld = (b & TB_QAM) != 0;
 	// --- right pad -> mouse motion with glide (mirrors mode_xinput's rfXboxMouse) ---
-	static int prx = 0, pry = 0;
-	static bool prt = false;
-	static float vx = 0, vy = 0, rmx = 0, rmy = 0;
 	bool rtouch = b & TB_RPADT;
 	int rx = s16off(r, 22), ry = s16off(r, 24);
 	if (rtouch) {
-		if (prt) {
-			vx += (rx - prx);
-			vy += (ry - pry);
+		if (ls.prt) {
+			ls.vx += (rx - ls.prx);
+			ls.vy += (ry - ls.pry);
 		}
-		prx = rx;
-		pry = ry;
+		ls.prx = rx;
+		ls.pry = ry;
 	}
-	prt = rtouch;
+	ls.prt = rtouch;
 
 	// Y inverted; *10 = desktop-cursor sensitivity (g_mDiv 64 -> eff 640). Lower g_mDiv via WebUI slider = faster.
-	float mxf = vx / (float)(g_mDiv * 10) + rmx,
-	      myf = -(vy / (float)(g_mDiv * 10)) + rmy;
+	float mxf = ls.vx / (float)(g_mDiv * 10) + ls.rmx,
+	      myf = -(ls.vy / (float)(g_mDiv * 10)) + ls.rmy;
 	int dx = (int)mxf, dy = (int)myf;
-	rmx = mxf - dx;
-	rmy = myf - dy; // sub-pixel carry
+	ls.rmx = mxf - dx;
+	ls.rmy = myf - dy; // sub-pixel carry
 	if (dx > 127)
 		dx = 127;
 	if (dx < -127)
@@ -39,28 +57,25 @@ void rfLizard(const uint8_t *r, Adafruit_USBD_HID *mdev,
 	if (dy < -127)
 		dy = -127;
 	float f = g_mFric / 100.0f;
-	vx *= f;
-	vy *= f;
-	if (vx > -1 && vx < 1)
-		vx = 0;
-	if (vy > -1 && vy < 1)
-		vy = 0; // friction = glide/decay
+	ls.vx *= f;
+	ls.vy *= f;
+	if (ls.vx > -1 && ls.vx < 1)
+		ls.vx = 0;
+	if (ls.vy > -1 && ls.vy < 1)
+		ls.vy = 0; // friction = glide/decay
 	// --- left pad -> vertical scroll wheel (no momentum; only while touching, coarse) ---
-	static int ply = 0;
-	static bool plt = false;
-	static float sacc = 0;
 	bool ltouch = b & TB_LPADT;
 	int ly = s16off(r, 18);
 	if (ltouch) {
-		if (plt) {
-			sacc += (ly - ply) / (float)(g_mDiv * 24);
+		if (ls.plt) {
+			ls.sacc += (ly - ls.ply) / (float)(g_mDiv * 24);
 		}
-		ply = ly;
+		ls.ply = ly;
 	} else
-		sacc = 0;
-	plt = ltouch;
-	int dw = (int)sacc;
-	sacc -= dw;
+		ls.sacc = 0;
+	ls.plt = ltouch;
+	int dw = (int)ls.sacc;
+	ls.sacc -= dw;
 	if (dw > 15)
 		dw = 15;
 	if (dw < -15)
@@ -75,9 +90,8 @@ void rfLizard(const uint8_t *r, Adafruit_USBD_HID *mdev,
 		mbtn |= 2; // left trigger  -> right click
 	if (b & TB_LPADC)
 		mbtn |= 4;
-	static uint8_t pmbtn = 0;
-	if (dx || dy || dw || mbtn != pmbtn) {
-		pmbtn = mbtn;
+	if (dx || dy || dw || mbtn != ls.pmbtn) {
+		ls.pmbtn = mbtn;
 		hid_mouse_report_t m;
 		m.buttons = mbtn;
 		m.x = (int8_t)dx;
@@ -115,26 +129,25 @@ void rfLizard(const uint8_t *r, Adafruit_USBD_HID *mdev,
 	LZK((b & TB_DRT) || sx > 12000, HID_KEY_ARROW_RIGHT);
 #undef LZK
 	if (g_usbMode == MODE_LIZARD) {
-		static bool prevL5 = false, prevR5 = false;
 		bool mh = (b & TB_STEAM) || qamHeld;
 		bool nL5 = mh && (b & TB_L5), nR5 = mh && (b & TB_R5);
-		if (nL5 && !prevL5) {
+		if (nL5 && !ls.prevL5) {
 			uint8_t cc = 0x02;
 			if (mdev->ready())
 				usbTxHid(mdev, 0x03, &cc, 1);
 		}
-		if (nR5 && !prevR5) {
+		if (nR5 && !ls.prevR5) {
 			uint8_t cc = 0x01;
 			if (mdev->ready())
 				usbTxHid(mdev, 0x03, &cc, 1);
 		}
-		if ((!nL5 && prevL5) || (!nR5 && prevR5)) {
+		if ((!nL5 && ls.prevL5) || (!nR5 && ls.prevR5)) {
 			uint8_t cc = 0x00;
 			if (mdev->ready())
 				usbTxHid(mdev, 0x03, &cc, 1);
 		}
-		prevL5 = nL5;
-		prevR5 = nR5;
+		ls.prevL5 = nL5;
+		ls.prevR5 = nR5;
 		if (mh && (b & TB_X)) {
 			mod = KEYBOARD_MODIFIER_LEFTGUI |
 			      KEYBOARD_MODIFIER_LEFTCTRL;
@@ -158,15 +171,14 @@ void rfLizard(const uint8_t *r, Adafruit_USBD_HID *mdev,
 			nk = 1;
 		}
 	}
-	static uint8_t pmod = 0, pkc[6] = { 0, 0, 0, 0, 0, 0 };
-	bool chg = (mod != pmod);
+	bool chg = (mod != ls.pmod);
 	for (int i = 0; i < 6; i++)
-		if (kc[i] != pkc[i])
+		if (kc[i] != ls.pkc[i])
 			chg = true;
 	if (chg) {
-		pmod = mod;
+		ls.pmod = mod;
 		for (int i = 0; i < 6; i++)
-			pkc[i] = kc[i];
+			ls.pkc[i] = kc[i];
 		uint8_t krep[8] = { mod,   0,	  kc[0], kc[1],
 				    kc[2], kc[3], kc[4], kc[5] };
 		if (kdev->ready())

+ 7 - 2
OpenPuck/mode_lizard.h

@@ -1,13 +1,18 @@
 // mode_lizard.h -- the controller's native "lizard" desktop behavior (driverless keyboard + mouse).
 //
 // Not a standalone IController: lizard rides ON the puck interface (puck_hid.cpp calls rfLizard when Steam is
-// closed), driving mouse(0x40)+keyboard(0x41) on the same puck HID slot. Canonical Valve SC1 map: right pad ->
+// closed), driving mouse(0x40)+keyboard(0x41) on the puck HID slot. Canonical Valve SC1 map: right pad ->
 // mouse (trackball glide), left pad -> scroll wheel + middle-click, R-trigger/R-pad-click -> left mouse,
 // L-trigger -> right mouse; A=Enter B=Esc X=PgUp Y=PgDn, d-pad/left-stick -> arrows, LB=LeftCtrl RB=LeftAlt,
 // View=Tab, Menu=Esc. Mouse reuses the Xbox-mode velocity+friction+sub-pixel glide model (g_mDiv / g_mFric).
+//
+// EVERY connected controller drives lizard independently: puck_hid.cpp calls rfLizard once per input report on
+// the report's own bond `slot`, routing to that slot's own HID interface. The OS merges multiple HID mice /
+// keyboards onto the one desktop, so all controllers move the cursor / type together. `slot` also indexes the
+// per-controller glide/edge state, so one controller's motion never clobbers another's.
 #pragma once
 #include <Adafruit_TinyUSB.h>
 #include <stdint.h>
 
-void rfLizard(const uint8_t *r, Adafruit_USBD_HID *mdev,
+void rfLizard(int slot, const uint8_t *r, Adafruit_USBD_HID *mdev,
 	      Adafruit_USBD_HID *kdev, uint8_t mrid, uint8_t krid);

+ 8 - 7
OpenPuck/puck_hid.cpp

@@ -428,9 +428,9 @@ void SteamPuckController::begin()
 
 // Forward the controller's report 0x45 to Steam, or drive lizard kb/mouse when Steam is closed. PURELY a
 // USB-side decision -- changes nothing about the RF poll or the host->controller relay. Per-slot: each
-// controller's 0x45 goes to its OWN hid[slot], so Steam sees four independent inputs. Lizard remains
-// single-controller (slot 0); the other slots stay quiet in lizard mode -- one mouse + one keyboard is
-// the only thing a desktop can consume, and the comment in mode_lizard.h documents this.
+// controller's 0x45 goes to its OWN hid[slot], so Steam sees four independent inputs. Lizard is likewise
+// per-slot now: each connected controller drives keyboard+mouse on its own hid[slot] (the OS merges the
+// several HID mice/keyboards onto the one desktop), so any controller -- on any bond slot -- works.
 void SteamPuckController::onReport45(int slot, const uint8_t *rep, bool fresh,
 				     uint8_t bodyTlen)
 {
@@ -450,10 +450,11 @@ void SteamPuckController::onReport45(int slot, const uint8_t *rep, bool fresh,
 	if (!g_slot[slot].used)
 		return;
 	if (lizardActive()) {
-		// Lizard single-controller: only slot 0's interface drives the mouse/keyboard. Other slots
-		// stay quiet in lizard mode.
-		if (slot == 0)
-			rfLizard(rep, &hid[0], &hid[0], 0x40, 0x41);
+		// Every connected controller drives keyboard+mouse on ITS OWN slot interface; the OS merges the
+		// multiple HID mice/keyboards onto the one desktop. (Was hardcoded to slot 0, which went silent
+		// whenever the live controller bonded to a non-zero slot -- e.g. slot 0 holding a stale/phantom
+		// bond from a cloned backup.) rfLizard keeps its glide/edge state per-slot so they don't clobber.
+		rfLizard(slot, rep, &hid[slot], &hid[slot], 0x40, 0x41);
 	} else {
 		uint8_t blen = bodyTlen - 1;
 		if (blen > 45)