├── .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 |
--------------------------------------------------------------------------------