├── .gitattributes ├── Gamepad.cpp ├── Gamepad.h ├── README.md └── examples ├── SimpleTest └── SimpleTest.ino └── ThumbsticksTest └── ThumbsticksTest.ino /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /Gamepad.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Gamepad.cpp 3 | A GamePad HID library for Arduino Pro Micro/Leonardo (ATMega32u4) 4 | 5 | Copyright (C) 2016 Marek GAMELASTER Kraus 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #include "Gamepad.h" 22 | 23 | #if defined(_USING_HID) 24 | 25 | Gamepad::Gamepad(bool useZRx) 26 | { 27 | if(useZRx) 28 | { 29 | static const uint8_t ReportDescriptor[] PROGMEM = { 30 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 31 | 0x09, 0x05, // USAGE (Game Pad) 32 | 0xa1, 0x01, // COLLECTION (Application) 33 | 0xa1, 0x00, // COLLECTION (Physical) 34 | 0x85, 0x03, // REPORT_ID (3) 35 | 0x05, 0x09, // USAGE_PAGE (Button) 36 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) 37 | 0x29, 0x10, // USAGE_MAXIMUM (Button 16) 38 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 39 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 40 | 0x75, 0x01, // REPORT_SIZE (1) 41 | 0x95, 0x10, // REPORT_COUNT (16) 42 | 0x81, 0x02, // INPUT (Data,Var,Abs) 43 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 44 | 0x09, 0x30, // USAGE (X) 45 | 0x09, 0x31, // USAGE (Y) 46 | 0x09, 0x32, // USAGE (Z) 47 | 0x09, 0x33, // USAGE (Rx) 48 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) 49 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 50 | 0x75, 0x08, // REPORT_SIZE (8) 51 | 0x95, 0x04, // REPORT_COUNT (4) 52 | 0x81, 0x02, // INPUT (Data,Var,Abs) 53 | 0xc0, // END_COLLECTION 54 | 0xc0 // END_COLLECTION 55 | }; 56 | static HIDSubDescriptor gamePadDescriptor(ReportDescriptor, sizeof(ReportDescriptor)); 57 | HID().AppendDescriptor(&gamePadDescriptor); 58 | } 59 | else 60 | { 61 | static const uint8_t ReportDescriptor[] PROGMEM = { 62 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 63 | 0x09, 0x05, // USAGE (Game Pad) 64 | 0xa1, 0x01, // COLLECTION (Application) 65 | 0xa1, 0x00, // COLLECTION (Physical) 66 | 0x85, 0x03, // REPORT_ID (3) 67 | 0x05, 0x09, // USAGE_PAGE (Button) 68 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) 69 | 0x29, 0x10, // USAGE_MAXIMUM (Button 16) 70 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 71 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 72 | 0x75, 0x01, // REPORT_SIZE (1) 73 | 0x95, 0x10, // REPORT_COUNT (16) 74 | 0x81, 0x02, // INPUT (Data,Var,Abs) 75 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 76 | 0x09, 0x30, // USAGE (X) 77 | 0x09, 0x31, // USAGE (Y) 78 | 0x09, 0x33, // USAGE (Rx) 79 | 0x09, 0x34, // USAGE (Ry) 80 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) 81 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 82 | 0x75, 0x08, // REPORT_SIZE (8) 83 | 0x95, 0x04, // REPORT_COUNT (4) 84 | 0x81, 0x02, // INPUT (Data,Var,Abs) 85 | 0xc0, // END_COLLECTION 86 | 0xc0 // END_COLLECTION 87 | }; 88 | static HIDSubDescriptor gamePadDescriptor(ReportDescriptor, sizeof(ReportDescriptor)); 89 | HID().AppendDescriptor(&gamePadDescriptor); 90 | } 91 | 92 | reportData.buttons = 0; 93 | reportData.leftXaxis = 0; 94 | reportData.leftYaxis = 0; 95 | reportData.rightXaxis = 0; 96 | reportData.rightYaxis = 0; 97 | } 98 | 99 | void Gamepad::setButtonState(uint8_t button, bool state) 100 | { 101 | if(state == true) bitSet(reportData.buttons, button); 102 | else bitClear(reportData.buttons, button); 103 | sendUpdate(); 104 | } 105 | 106 | void Gamepad::setLeftXaxis (int8_t value) 107 | { 108 | reportData.leftXaxis = value; 109 | sendUpdate(); 110 | } 111 | 112 | void Gamepad::setLeftYaxis (int8_t value) 113 | { 114 | reportData.leftYaxis = value; 115 | sendUpdate(); 116 | } 117 | 118 | void Gamepad::setRightXaxis(int8_t value) 119 | { 120 | reportData.rightXaxis = value; 121 | sendUpdate(); 122 | } 123 | 124 | void Gamepad::setRightYaxis(int8_t value) 125 | { 126 | reportData.rightYaxis = value; 127 | sendUpdate(); 128 | } 129 | 130 | void Gamepad::sendUpdate() 131 | { 132 | HID().SendReport(0x03, &reportData, sizeof(gamepad_report_struct)); 133 | } 134 | #endif -------------------------------------------------------------------------------- /Gamepad.h: -------------------------------------------------------------------------------- 1 | /* 2 | Gamepad.h 3 | A GamePad HID library for Arduino Pro Micro/Leonardo (ATMega32u4) 4 | 5 | Copyright (C) 2016 Marek GAMELASTER Kraus 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #ifndef GAMEPAD_H 22 | #define GAMEPAD_H 23 | 24 | #include "HID.h" 25 | 26 | #if defined(_USING_HID) 27 | 28 | typedef struct 29 | { 30 | uint16_t buttons; 31 | int8_t leftXaxis; 32 | int8_t leftYaxis; 33 | int8_t rightXaxis; 34 | int8_t rightYaxis; 35 | //TODO: implement a R2 and L2 throttles or what it is 36 | } gamepad_report_struct; 37 | 38 | class Gamepad 39 | { 40 | private: 41 | gamepad_report_struct reportData; 42 | public: 43 | Gamepad(bool useZRx = false); 44 | 45 | void sendUpdate(); 46 | 47 | void setButtonState(uint8_t button, bool state); 48 | void setLeftXaxis (int8_t value); 49 | void setLeftYaxis (int8_t value); 50 | void setRightXaxis(int8_t value); 51 | void setRightYaxis(int8_t value); 52 | 53 | }; 54 | 55 | #else 56 | #warning "HID is not supported for this chip" 57 | #endif 58 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArduinoGamepad 2 | A GamePad HID library for Arduino Pro Micro/Leonardo (ATMega32u4) 3 | This library works only on Arduino IDE 1.6.6 or higher! 4 | ## How to install 5 | Create a new directory named "Gamepad" in Documents > Arduino > libraries, and copy all files from repository into that directory 6 | ## How to make a Gamepad 7 | [http://www.instructables.com/id/Arduino-LeonardoMicroATMega32u4-As-GamepadGame-Con/](http://www.instructables.com/id/Arduino-LeonardoMicroATMega32u4-As-GamepadGame-Con/) 8 | ## Small example 9 | ```c++ 10 | //Including a library 11 | #include 12 | 13 | //Initializing a Gamepad 14 | Gamepad gp; 15 | 16 | int buttonIndex = 0; 17 | bool setState = true; 18 | 19 | void setup() { 20 | 21 | } 22 | 23 | void loop() { 24 | gp.setButtonState(buttonIndex++, setState); 25 | if(buttonIndex == 16) 26 | { 27 | setState = !setState; //negate the value 28 | buttonIndex = 0; 29 | } 30 | delay(500); 31 | } 32 | ``` 33 | ## How to test gamepad 34 | - Just try a game what supports a normal GamePad (not X360, if you want to play game whats support only X360, use [X360CE](https://github.com/x360ce/x360ce)) 35 | - Or use a Windows Devices "Tester" (where is option to calibrate a GamePad, but I recommending a Arduinos calibration in example project): Go to Control Panel > Devices and Printers and search your device (for me its a Arduino Leonardo) > Right click > Settings of game device > Properties > Test 36 | 37 | ## Functions reference 38 | 39 | ### Gamepad(bool useZRx = false) 40 | Initializing a USB HID Descriptor 41 | - `boolean` useZRx (default `false`): Z is used to represent the right stick’s X axis, Rx is used to represent the right stick’s Y axis. This doesn’t make sense but this is how most existing USB game pads work. I have tested this using Battlefield Bad Company 2, it works. [SOURCE](http://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/) 42 | 43 | ### sendUpdate() 44 | Sending a update report, its not needed to use, its executed automatically 45 | 46 | ### setButtonState(uint8_t button, bool state) 47 | Setting a Button State 48 | - `uint8_t` button - Number of button (0 - 15), Button #1 is 0, Button #2 is 1 etc... 49 | - `bool` state - `true` is pressed, `false` is released 50 | 51 | ### setLeftXaxis(uint8_t axis) 52 | Setting an "axis" for Left Thumbstick X Axis 53 | - `uint8_t` axis - a value from -127 to 127, when 0 means center (you must format a values from real Thumbsticks to this ranges) 54 | 55 | ### setLeftYaxis(uint8_t axis) 56 | Setting an "axis" for Left Thumbstick Y Axis 57 | - `uint8_t` axis - a value from -127 to 127, when 0 means center (you must format a values from real Thumbsticks to this ranges) 58 | 59 | ### setRightXaxis(uint8_t axis) 60 | Setting an "axis" for Right Thumbstick X Axis 61 | - `uint8_t` axis - a value from -127 to 127, when 0 means center (you must format a values from real Thumbsticks to this ranges) 62 | 63 | ### setRightYaxis(uint8_t axis) 64 | Setting an "axis" for Right Thumbstick Y Axis 65 | - `uint8_t` axis - a value from -127 to 127, when 0 means center (you must format a values from real Thumbsticks to this ranges) 66 | 67 | -------------------------------------------------------------------------------- /examples/SimpleTest/SimpleTest.ino: -------------------------------------------------------------------------------- 1 | //Including a library 2 | #include 3 | 4 | //Initializing a Gamepad 5 | Gamepad gp; 6 | 7 | int buttonIndex = 0; 8 | bool setState = true; 9 | 10 | void setup() { 11 | 12 | } 13 | 14 | void loop() { 15 | gp.setButtonState(buttonIndex++, setState); 16 | if(buttonIndex == 16) 17 | { 18 | setState = !setState; //negate the value 19 | buttonIndex = 0; 20 | } 21 | delay(500); 22 | } -------------------------------------------------------------------------------- /examples/ThumbsticksTest/ThumbsticksTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Example of working 2 Thumbsticks (PS2 Thumbstick for Arduino) with Calibration 3 | * Connect first thumbstick X to A1, Y to A0 4 | * second thumbstick X to A3,Y to A2 5 | */ 6 | //including a library 7 | #include 8 | 9 | //initialize a centers of axises for calibration 10 | int rightXcenter = 500; 11 | int rightYcenter = 500; 12 | int leftXcenter = 500; 13 | int leftYcenter = 500; 14 | double multiplierRX = 0.254; //127 / 500 15 | double multiplierRY = 0.254; 16 | double multiplierLX = 0.254; 17 | double multiplierLY = 0.254; 18 | 19 | //Initializing a Gamepad 20 | Gamepad gp; 21 | void setup() { 22 | //initializing inputs 23 | pinMode(A0, INPUT); 24 | pinMode(A1, INPUT); 25 | pinMode(A2, INPUT); 26 | pinMode(A3, INPUT); 27 | pinMode(3, INPUT_PULLUP); 28 | pinMode(4, INPUT_PULLUP); 29 | calibrate(); 30 | } 31 | 32 | void loop() { 33 | int lx, ly, rx, ry; 34 | lx = analogRead(A3); 35 | ly = analogRead(A2); 36 | rx = analogRead(A1); 37 | ry = analogRead(A0); 38 | //we need to convert a 0-1000 to -127 - 127 39 | lx = floor((lx - leftXcenter) * multiplierLX); 40 | ly = floor((ly - leftYcenter) * multiplierLY); 41 | rx = floor((rx - rightXcenter) * multiplierRX); 42 | ry = floor((ry - rightYcenter) * multiplierRY); 43 | if(lx > 127) lx = 127; 44 | if(ly > 127) ly = 127; 45 | if(rx > 127) rx = 127; 46 | if(ry > 127) ry = 127; 47 | gp.setLeftXaxis(lx); 48 | gp.setRightXaxis(rx); 49 | //because i have placed a thumbstick in breadboard, i must invert a Y axis and swap X and Y axises 50 | gp.setLeftYaxis(ly); 51 | gp.setRightYaxis(ry); 52 | 53 | int rightStickButton, leftStickButton; 54 | rightStickButton = digitalRead(3); 55 | leftStickButton = digitalRead(4); 56 | 57 | if(rightStickButton == LOW) 58 | gp.setButtonState(11, true); 59 | else 60 | gp.setButtonState(11, false); 61 | 62 | if(leftStickButton == LOW) 63 | gp.setButtonState(10, true); 64 | else 65 | gp.setButtonState(10, false); 66 | 67 | delay(20); 68 | } 69 | 70 | void calibrate() 71 | { 72 | int lx, ly, rx, ry; 73 | int i = 0; 74 | while(i < 8) 75 | { 76 | lx = analogRead(A3); 77 | ly = analogRead(A2); 78 | rx = analogRead(A1); 79 | ry = analogRead(A0); 80 | bool validLX = lx > (leftXcenter - 100) && lx < (leftXcenter + 100); 81 | bool validLY = ly > (leftYcenter - 100) && ly < (leftYcenter + 100); 82 | bool validRX = rx > (rightXcenter - 100) && rx < (rightXcenter + 100); 83 | bool validRY = ry > (rightYcenter - 100) && ry < (rightYcenter + 100); 84 | if(validLX && validLY && validRX && validRY) 85 | { 86 | i++; 87 | //nothing to do here! 88 | } 89 | else i = 0; 90 | delay(20); 91 | } 92 | leftXcenter = lx; 93 | leftYcenter = ly; 94 | rightXcenter = rx; 95 | rightYcenter = ry; 96 | multiplierLX = (double)127 / (double)lx; 97 | multiplierLY = (double)127 / (double)ly; 98 | multiplierRX = (double)127 / (double)rx; 99 | multiplierRY = (double)127 / (double)ry; 100 | } 101 | --------------------------------------------------------------------------------