mode_switch_hori.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // mode_switch_hori.c — Switch HORIPAD emulated controller (ported from OpenPuck).
  2. //
  3. // 8-byte report, no report id: [btn_lo][btn_hi][hat][LX][LY][RX][RY][vendor].
  4. // Nintendo face layout (A↔B / X↔Y swapped). No rumble/features.
  5. //
  6. // SPDX-License-Identifier: AGPL-3.0-or-later
  7. #include "puck/emu.h"
  8. #include "puck/gamepad_util.h"
  9. static const uint8_t SWITCH_HID_DESC[] = {
  10. 0x05, 0x01, 0x09, 0x05, 0xA1, 0x01, 0x15, 0x00, 0x25, 0x01, 0x35, 0x00,
  11. 0x45, 0x01, 0x75, 0x01, 0x95, 0x10,
  12. 0x05, 0x09, 0x19, 0x01, 0x29, 0x10, 0x81, 0x02, 0x05, 0x01, 0x25, 0x07,
  13. 0x46, 0x3B, 0x01, 0x75, 0x04, 0x95, 0x01, 0x65, 0x14, 0x09, 0x39, 0x81,
  14. 0x42,
  15. 0x65, 0x00, 0x95, 0x01, 0x81, 0x01,
  16. 0x26, 0xFF, 0x00, 0x46, 0xFF, 0x00, 0x09, 0x30, 0x09, 0x31, 0x09, 0x32,
  17. 0x09, 0x35, 0x75, 0x08, 0x95, 0x04, 0x81, 0x02,
  18. 0x06, 0x00, 0xFF, 0x09, 0x20, 0x95, 0x01, 0x81, 0x02,
  19. 0x0A, 0x21, 0x26, 0x95, 0x08, 0x91, 0x02, 0xC0
  20. };
  21. static uint16_t hori_build(int slot, uint8_t *out, uint8_t *rid)
  22. {
  23. *rid = 0;
  24. uint32_t b = g_in[slot].buttons;
  25. uint16_t btn = 0;
  26. // Nintendo layout (abSwap): A→B(0x02) B→A(0x04) X→Y(0x01) Y→X(0x08).
  27. if (b & TB_A) btn |= 0x02;
  28. if (b & TB_B) btn |= 0x04;
  29. if (b & TB_X) btn |= 0x01;
  30. if (b & TB_Y) btn |= 0x08;
  31. if (b & TB_LB) btn |= 0x10;
  32. if (b & TB_RB) btn |= 0x20;
  33. if (g_in[slot].lt >= SW_TRIG_ON || (b & TB_L2)) btn |= 0x40; // ZL
  34. if (g_in[slot].rt >= SW_TRIG_ON || (b & TB_R2)) btn |= 0x80; // ZR
  35. if (b & TB_MENU) btn |= 0x100; // Minus
  36. if (b & TB_VIEW) btn |= 0x200; // Plus
  37. if (b & TB_L3) btn |= 0x400;
  38. if (b & TB_R3) btn |= 0x800;
  39. if (b & TB_STEAM) btn |= 0x1000; // Home
  40. if (b & TB_QAM) btn |= 0x2000; // Capture
  41. bool u = b & TB_DUP, d = b & TB_DDN, l = b & TB_DLF, r = b & TB_DRT;
  42. uint8_t hat = 8;
  43. if (u && r) hat = 1; else if (r && d) hat = 3;
  44. else if (d && l) hat = 5; else if (l && u) hat = 7;
  45. else if (u) hat = 0; else if (r) hat = 2;
  46. else if (d) hat = 4; else if (l) hat = 6;
  47. out[0] = (uint8_t)(btn & 0xFF);
  48. out[1] = (uint8_t)(btn >> 8);
  49. out[2] = hat;
  50. out[3] = sw_stick(g_in[slot].lx, false);
  51. out[4] = sw_stick(g_in[slot].ly, true);
  52. out[5] = sw_stick(g_in[slot].rx, false);
  53. out[6] = sw_stick(g_in[slot].ry, true);
  54. out[7] = 0;
  55. return 8;
  56. }
  57. const emu_mode_t emu_switch_hori = {
  58. .vid = 0x0F0D, .pid = 0x0092, .bcd = 0x0210,
  59. .product = "POKKEN CONTROLLER",
  60. .report_desc = SWITCH_HID_DESC,
  61. .report_desc_len = sizeof(SWITCH_HID_DESC),
  62. .build = hori_build,
  63. .get_report = NULL,
  64. .set_report = NULL,
  65. .poll_ms = 4,
  66. };