mode_lizard.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include "mode_lizard.h"
  2. #include "triton.h"
  3. #include "config.h"
  4. #include "usb_tx.h"
  5. #include "bonds.h" // NSLOT
  6. // Per-controller lizard state. rfLizard runs once per input report on the report's bond slot, so the glide
  7. // velocity / sub-pixel carry / button + keyboard edge trackers must be PER SLOT -- shared statics would let
  8. // one controller's motion clobber another's (garbage deltas). Zero-init (static storage) matches the old
  9. // per-function initial values (all 0 / false).
  10. struct LizardState {
  11. int prx, pry; // last right-pad sample (mouse)
  12. bool prt; // right pad was touched last frame
  13. float vx, vy, rmx, rmy; // mouse velocity + sub-pixel carry
  14. int ply; // last left-pad Y (scroll)
  15. bool plt; // left pad was touched last frame
  16. float sacc; // scroll accumulator
  17. uint8_t pmbtn; // last mouse-button mask
  18. bool prevL5, prevR5; // MODE_LIZARD media-key edges (L5/R5)
  19. uint8_t pmod, pkc[6]; // last keyboard modifier + keycodes (edge-send)
  20. };
  21. static LizardState g_lz[NSLOT];
  22. void rfLizard(int slot, const uint8_t *r, Adafruit_USBD_HID *mdev,
  23. Adafruit_USBD_HID *kdev, uint8_t mrid, uint8_t krid)
  24. {
  25. if (slot < 0 || slot >= NSLOT)
  26. return;
  27. LizardState &ls = g_lz[slot];
  28. uint32_t b = btnsOf(r);
  29. bool qamHeld = (b & TB_QAM) != 0;
  30. // --- right pad -> mouse motion with glide (mirrors mode_xinput's rfXboxMouse) ---
  31. bool rtouch = b & TB_RPADT;
  32. int rx = s16off(r, 22), ry = s16off(r, 24);
  33. if (rtouch) {
  34. if (ls.prt) {
  35. ls.vx += (rx - ls.prx);
  36. ls.vy += (ry - ls.pry);
  37. }
  38. ls.prx = rx;
  39. ls.pry = ry;
  40. }
  41. ls.prt = rtouch;
  42. // Y inverted; *10 = desktop-cursor sensitivity (g_mDiv 64 -> eff 640). Lower g_mDiv via WebUI slider = faster.
  43. float mxf = ls.vx / (float)(g_mDiv * 10) + ls.rmx,
  44. myf = -(ls.vy / (float)(g_mDiv * 10)) + ls.rmy;
  45. int dx = (int)mxf, dy = (int)myf;
  46. ls.rmx = mxf - dx;
  47. ls.rmy = myf - dy; // sub-pixel carry
  48. if (dx > 127)
  49. dx = 127;
  50. if (dx < -127)
  51. dx = -127;
  52. if (dy > 127)
  53. dy = 127;
  54. if (dy < -127)
  55. dy = -127;
  56. float f = g_mFric / 100.0f;
  57. ls.vx *= f;
  58. ls.vy *= f;
  59. if (ls.vx > -1 && ls.vx < 1)
  60. ls.vx = 0;
  61. if (ls.vy > -1 && ls.vy < 1)
  62. ls.vy = 0; // friction = glide/decay
  63. // --- left pad -> vertical scroll wheel (no momentum; only while touching, coarse) ---
  64. bool ltouch = b & TB_LPADT;
  65. int ly = s16off(r, 18);
  66. if (ltouch) {
  67. if (ls.plt) {
  68. ls.sacc += (ly - ls.ply) / (float)(g_mDiv * 24);
  69. }
  70. ls.ply = ly;
  71. } else
  72. ls.sacc = 0;
  73. ls.plt = ltouch;
  74. int dw = (int)ls.sacc;
  75. ls.sacc -= dw;
  76. if (dw > 15)
  77. dw = 15;
  78. if (dw < -15)
  79. dw = -15; // finger up = wheel up (positive)
  80. // --- mouse buttons: left=R-pad-click|R-trigger, right=L-trigger, middle=L-pad-click ---
  81. // trigU8 scales full-range so a full pull reaches ~0xFF; a raw >>8 tops out ~0x80, never crossing threshold.
  82. uint8_t rtrig = trigU8(u16off(r, 6)), ltrig = trigU8(u16off(r, 4));
  83. uint8_t mbtn = 0;
  84. if ((b & TB_RPADC) || rtrig > 180)
  85. mbtn |= 1; // right trigger -> left (primary) click
  86. if (ltrig > 180)
  87. mbtn |= 2; // left trigger -> right click
  88. if (b & TB_LPADC)
  89. mbtn |= 4;
  90. if (dx || dy || dw || mbtn != ls.pmbtn) {
  91. ls.pmbtn = mbtn;
  92. hid_mouse_report_t m;
  93. m.buttons = mbtn;
  94. m.x = (int8_t)dx;
  95. m.y = (int8_t)dy;
  96. m.wheel = (int8_t)dw;
  97. m.pan = 0;
  98. if (mdev->ready())
  99. usbTxHid(mdev, mrid, &m, sizeof m);
  100. }
  101. // --- keyboard: modifiers + up to 6 keycodes ---
  102. uint8_t mod = 0, kc[6] = { 0, 0, 0, 0, 0, 0 }, nk = 0;
  103. if (b & TB_LB)
  104. mod |= KEYBOARD_MODIFIER_LEFTCTRL;
  105. if (b & TB_RB)
  106. mod |= KEYBOARD_MODIFIER_LEFTALT;
  107. #define LZK(cond, code) \
  108. do { \
  109. if ((cond) && nk < 6) \
  110. kc[nk++] = (code); \
  111. } while (0)
  112. LZK(b & TB_A, HID_KEY_ENTER);
  113. LZK(b & TB_B, HID_KEY_ESCAPE);
  114. LZK(b & TB_X, HID_KEY_PAGE_UP);
  115. LZK(b & TB_Y, HID_KEY_PAGE_DOWN);
  116. LZK(b & TB_VIEW,
  117. (g_usbMode == MODE_LIZARD) ? HID_KEY_ESCAPE : HID_KEY_TAB);
  118. LZK(b & TB_MENU,
  119. (g_usbMode == MODE_LIZARD) ? HID_KEY_TAB : HID_KEY_ESCAPE);
  120. // left stick (XInput sign: +Y = up); deflect ~37% acts as a d-pad
  121. int sx = s16off(r, 8), sy = s16off(r, 10);
  122. LZK((b & TB_DUP) || sy > 12000, HID_KEY_ARROW_UP);
  123. LZK((b & TB_DDN) || sy < -12000, HID_KEY_ARROW_DOWN);
  124. LZK((b & TB_DLF) || sx < -12000, HID_KEY_ARROW_LEFT);
  125. LZK((b & TB_DRT) || sx > 12000, HID_KEY_ARROW_RIGHT);
  126. #undef LZK
  127. if (g_usbMode == MODE_LIZARD) {
  128. bool mh = (b & TB_STEAM) || qamHeld;
  129. bool nL5 = mh && (b & TB_L5), nR5 = mh && (b & TB_R5);
  130. if (nL5 && !ls.prevL5) {
  131. uint8_t cc = 0x02;
  132. if (mdev->ready())
  133. usbTxHid(mdev, 0x03, &cc, 1);
  134. }
  135. if (nR5 && !ls.prevR5) {
  136. uint8_t cc = 0x01;
  137. if (mdev->ready())
  138. usbTxHid(mdev, 0x03, &cc, 1);
  139. }
  140. if ((!nL5 && ls.prevL5) || (!nR5 && ls.prevR5)) {
  141. uint8_t cc = 0x00;
  142. if (mdev->ready())
  143. usbTxHid(mdev, 0x03, &cc, 1);
  144. }
  145. ls.prevL5 = nL5;
  146. ls.prevR5 = nR5;
  147. if (mh && (b & TB_X)) {
  148. mod = KEYBOARD_MODIFIER_LEFTGUI |
  149. KEYBOARD_MODIFIER_LEFTCTRL;
  150. kc[0] = HID_KEY_O;
  151. kc[1] = 0;
  152. kc[2] = 0;
  153. kc[3] = 0;
  154. kc[4] = 0;
  155. kc[5] = 0;
  156. nk = 1;
  157. }
  158. if (mh && (b & TB_L4)) {
  159. mod = KEYBOARD_MODIFIER_LEFTCTRL |
  160. KEYBOARD_MODIFIER_LEFTALT;
  161. kc[0] = HID_KEY_DELETE;
  162. kc[1] = 0;
  163. kc[2] = 0;
  164. kc[3] = 0;
  165. kc[4] = 0;
  166. kc[5] = 0;
  167. nk = 1;
  168. }
  169. }
  170. bool chg = (mod != ls.pmod);
  171. for (int i = 0; i < 6; i++)
  172. if (kc[i] != ls.pkc[i])
  173. chg = true;
  174. if (chg) {
  175. ls.pmod = mod;
  176. for (int i = 0; i < 6; i++)
  177. ls.pkc[i] = kc[i];
  178. uint8_t krep[8] = { mod, 0, kc[0], kc[1],
  179. kc[2], kc[3], kc[4], kc[5] };
  180. if (kdev->ready())
  181. usbTxHid(kdev, krid, krep, 8);
  182. }
  183. }