#ifndef GAMEPAD_COMMON_H #define GAMEPAD_COMMON_H #include #include "HIDTypes.h" #if GAMEPAD_OUTPUT == 5 // nintendo switch #include "HID-Project.h" #define BUTTON_A NSButton_A #define BUTTON_B NSButton_B #define BUTTON_MENU NSButton_Home #define BUTTON_X NSButton_X #define BUTTON_Y NSButton_Y #define BUTTON_TL NSButton_LeftTrigger #define BUTTON_TR NSButton_RightTrigger #define BUTTON_TL2 NSButton_LeftThrottle #define BUTTON_TR2 NSButton_RightThrottle #define BUTTON_SELECT NSButton_Minus #define BUTTON_START NSButton_Plus #define BUTTON_THUMBL NSButton_LeftStick #define BUTTON_THUMBR NSButton_RightStick #define DPAD_CENTER NSGAMEPAD_DPAD_CENTERED #define DPAD_UP NSGAMEPAD_DPAD_UP #define DPAD_UP_RIGHT NSGAMEPAD_DPAD_UP_RIGHT #define DPAD_RIGHT NSGAMEPAD_DPAD_RIGHT #define DPAD_DOWN_RIGHT NSGAMEPAD_DPAD_DOWN_RIGHT #define DPAD_DOWN NSGAMEPAD_DPAD_DOWN #define DPAD_DOWN_LEFT NSGAMEPAD_DPAD_DOWN_LEFT #define DPAD_LEFT NSGAMEPAD_DPAD_LEFT #define DPAD_UP_LEFT NSGAMEPAD_DPAD_UP_LEFT #define AXIS_CENTER 128 #define AXIS_MAX 255 #define AXIS_MIN 0 // not supported by horipad yet... #define TRIGGER_MAX 255 #define TRIGGER_MIN 0 #else #define BUTTON_A 1 #define BUTTON_B 2 #define BUTTON_MENU 4 #define BUTTON_X 8 #define BUTTON_Y 16 #define BUTTON_TL 64 #define BUTTON_TR 128 #define BUTTON_TL2 256 #define BUTTON_TR2 512 #define BUTTON_SELECT 1024 #define BUTTON_START 2048 #define BUTTON_THUMBL 8192 #define BUTTON_THUMBR 16384 #define DPAD_CENTER 0 #define DPAD_UP 1 #define DPAD_UP_RIGHT 2 #define DPAD_RIGHT 3 #define DPAD_DOWN_RIGHT 4 #define DPAD_DOWN 5 #define DPAD_DOWN_LEFT 6 #define DPAD_LEFT 7 #define DPAD_UP_LEFT 8 #define AXIS_CENTER 0 #define AXIS_MAX 32767 #define AXIS_MIN -32767 #define TRIGGER_MAX 255 #define TRIGGER_MIN 0 #endif // nintendo switch // aliases #define BUTTON_HOME BUTTON_MENU #define BUTTON_MINUS BUTTON_SELECT #define BUTTON_PLUS BUTTON_START #define BUTTON_L BUTTON_TL #define BUTTON_L1 BUTTON_TL #define BUTTON_R BUTTON_TR #define BUTTON_R1 BUTTON_TR #define BUTTON_L2 BUTTON_TL2 #define BUTTON_R2 BUTTON_TR2 #define BUTTON_L3 BUTTON_THUMBL #define BUTTON_R3 BUTTON_THUMBR #define DPAD_CENTERED DPAD_CENTER // end aliases #ifndef AXIS_CENTER_IN #define AXIS_CENTER_IN 0 #endif #ifndef AXIS_MAX_IN #define AXIS_MAX_IN 32767 #endif #ifndef AXIS_MIN_IN #define AXIS_MIN_IN -32767 #endif #ifndef TRIGGER_MAX_IN #define TRIGGER_MAX_IN 127 #endif #ifndef TRIGGER_MIN_IN #define TRIGGER_MIN_IN -127 #endif #if 0 #define BUTTON_1 1 #define BUTTON_2 2 #define BUTTON_3 4 #define BUTTON_4 8 #define BUTTON_5 16 #define BUTTON_6 32 #define BUTTON_7 64 #define BUTTON_8 128 #define BUTTON_9 256 #define BUTTON_10 512 #define BUTTON_11 1024 #define BUTTON_12 2048 #define BUTTON_13 4096 #define BUTTON_14 8192 #define BUTTON_15 16384 #define BUTTON_16 32768 #define BUTTON_17 65536 #define BUTTON_18 131072 #define BUTTON_19 262144 #define BUTTON_20 524288 #define BUTTON_21 1048576 #define BUTTON_22 2097152 #define BUTTON_23 4194304 #define BUTTON_24 8388608 #define BUTTON_25 16777216 #define BUTTON_26 33554432 #define BUTTON_27 67108864 #define BUTTON_28 134217728 #define BUTTON_29 268435456 #define BUTTON_30 536870912 #define BUTTON_31 1073741824 #define BUTTON_32 2147483648 #endif #define DPAD_BIT_UP 1 #define DPAD_BIT_DOWN 2 #define DPAD_BIT_LEFT 4 #define DPAD_BIT_RIGHT 8 #ifndef GAMEPAD_REPORT_ARRAY_ADD // this is used by radio gamepad to send additional info #define GAMEPAD_REPORT_ARRAY_ADD 0 #endif // this must match _hidReportDescriptor, length to actually send #define GAMEPAD_REPORT_LEN 15 static const uint8_t _hidReportDescriptor[] PROGMEM = { USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) USAGE(1), 0x05, // USAGE (Gamepad) COLLECTION(1), 0x01, // COLLECTION (Application) USAGE(1), 0x01, // USAGE (Pointer) COLLECTION(1), 0x00, // COLLECTION (Physical) // ------------------------------------------------- Buttons (1 to 32) USAGE_PAGE(1), 0x09, // USAGE_PAGE (Button) USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (Button 1) USAGE_MAXIMUM(1), 0x20, // USAGE_MAXIMUM (Button 32) LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) REPORT_COUNT(1), 0x20, // REPORT_COUNT (32) HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;32 button bits // ------------------------------------------------- X/Y position, Z/rZ position USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) COLLECTION(1), 0x00, // COLLECTION (Physical) USAGE(1), 0x30, // USAGE (X) USAGE(1), 0x31, // USAGE (Y) USAGE(1), 0x32, // USAGE (Z) USAGE(1), 0x35, // USAGE (rZ) 0x16, 0x01, 0x80, //LOGICAL_MINIMUM (-32767) 0x26, 0xFF, 0x7F, //LOGICAL_MAXIMUM (32767) REPORT_SIZE(1), 0x10, // REPORT_SIZE (16) REPORT_COUNT(1), 0x04, // REPORT_COUNT (4) HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs) // ------------------------------------------------- Triggers USAGE(1), 0x33, // USAGE (rX) Left Trigger USAGE(1), 0x34, // USAGE (rY) Right Trigger LOGICAL_MINIMUM(1), 0x81, // LOGICAL_MINIMUM (-127) LOGICAL_MAXIMUM(1), 0x7f, // LOGICAL_MAXIMUM (127) REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) REPORT_COUNT(1), 0x02, // REPORT_COUNT (2) HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;4 bytes (X,Y,Z,rZ) END_COLLECTION(0), // END_COLLECTION USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) USAGE(1), 0x39, // USAGE (Hat switch) USAGE(1), 0x39, // USAGE (Hat switch) LOGICAL_MINIMUM(1), 0x01, // LOGICAL_MINIMUM (1) LOGICAL_MAXIMUM(1), 0x08, // LOGICAL_MAXIMUM (8) REPORT_SIZE(1), 0x04, // REPORT_SIZE (4) REPORT_COUNT(1), 0x02, // REPORT_COUNT (2) HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;1 byte Hat1, Hat2 END_COLLECTION(0), // END_COLLECTION END_COLLECTION(0) // END_COLLECTION }; class AbstractGamepad { public: uint32_t _buttons[GAMEPAD_COUNT]; uint8_t _dpad[GAMEPAD_COUNT]; uint8_t gamepadReport[GAMEPAD_REPORT_LEN + GAMEPAD_REPORT_ARRAY_ADD]; AbstractGamepad() { } virtual void begin(void) { } virtual void end(void) { } virtual bool isConnected(void) { return true; } virtual void setAxis(const uint8_t cIdx, int16_t x, int16_t y, int16_t z, int16_t rZ, char rX, char rY, signed char hat) { if (x == -32768) { x = -32767; } if (y == -32768) { y = -32767; } if (z == -32768) { z = -32767; } if (rZ == -32768) { rZ = -32767; } gamepadReport[0] = _buttons[cIdx]; gamepadReport[1] = (_buttons[cIdx] >> 8); gamepadReport[2] = (_buttons[cIdx] >> 16); gamepadReport[3] = (_buttons[cIdx] >> 24); gamepadReport[4] = x; gamepadReport[5] = (x >> 8); gamepadReport[6] = y; gamepadReport[7] = (y >> 8); gamepadReport[8] = z; gamepadReport[9] = (z >> 8); gamepadReport[10] = rZ; gamepadReport[11] = (rZ >> 8); gamepadReport[12] = (signed char)(rX - 128); gamepadReport[13] = (signed char)(rY - 128); gamepadReport[14] = hat; if (gamepadReport[12] == -128) { gamepadReport[12] = -127; } if (gamepadReport[13] == -128) { gamepadReport[13] = -127; } this->sync(cIdx); } virtual void setHatSync(const uint8_t cIdx, signed char hat) { setAxis(cIdx, AXIS_CENTER, AXIS_CENTER, AXIS_CENTER, AXIS_CENTER, 0, 0, hat); } virtual void buttons(const uint8_t cIdx, uint32_t b) { _buttons[cIdx] = b; } virtual void press(const uint8_t cIdx, uint32_t b) { buttons(cIdx, _buttons[cIdx] | b); } virtual void release(const uint8_t cIdx, uint32_t b) { buttons(cIdx, _buttons[cIdx] & ~b); } virtual bool isPressed(const uint8_t cIdx, uint32_t b) { return ((b & _buttons[cIdx]) > 0); } virtual void dpad(const uint8_t cIdx, uint8_t b) { _dpad[cIdx] = b; } virtual void pressDpad(const uint8_t cIdx, uint8_t b) { dpad(cIdx, _dpad[cIdx] | b); } virtual void releaseDpad(const uint8_t cIdx, uint8_t b) { dpad(cIdx, _dpad[cIdx] & ~b); } virtual bool isDpadPressed(const uint8_t cIdx, uint8_t b) { return ((b & _dpad[cIdx]) > 0); } virtual void sync(const uint8_t cIdx) { sendHidReport(cIdx, &gamepadReport, GAMEPAD_REPORT_LEN); } virtual void reset(const uint8_t cIdx) { _buttons[cIdx] = 0; _dpad[cIdx] = 0; } virtual char getHat(const uint8_t cIdx) { // bit positions are B0000RLDU switch (_dpad[cIdx]) { case B00000000: return DPAD_CENTER; case B00000001: return DPAD_UP; case B00000010: return DPAD_DOWN; case B00000100: return DPAD_LEFT; case B00001000: return DPAD_RIGHT; case B00001001: return DPAD_UP_RIGHT; case B00001010: return DPAD_DOWN_RIGHT; case B00000110: return DPAD_DOWN_LEFT; case B00000101: return DPAD_UP_LEFT; } return DPAD_CENTER; } // actually sends report virtual void sendHidReport(const uint8_t cIdx, const void* d, int len) { } virtual ~AbstractGamepad() { } }; class ScratchGamepad : public AbstractGamepad { public: ScratchGamepad() : AbstractGamepad() { } virtual boolean changed(const uint8_t cIdx, AbstractGamepad& current) { if (_buttons[cIdx] != current._buttons[cIdx] || _dpad[cIdx] != current._dpad[cIdx]) { current._dpad[cIdx] = _dpad[cIdx]; current._buttons[cIdx] = _buttons[cIdx]; return true; } return false; } }; #endif // GAMEPAD_COMMON_H