Page 1 of 1

HID Gamepad - not more than 16 buttons?

Posted: Tue Sep 09, 2014 11:33 pm
by MrOnak
Is there a limit as to how many digital buttons a HID gamepad supports?

When I increase the USAGE_MAXIMUM beyond "Button 16" my computer doesn't accept any inputs from the device anymore - not from any of the buttons, nor from the analog axis.

My working HID descriptor:

Code: Select all

PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
   0x05, 0x01,         // USAGE_PAGE (Generic Desktop)
   0x09, 0x05,         // USAGE (Game Pad)
   0xa1, 0x01,         // COLLECTION (Application)
   0xa1, 0x00,         //   COLLECTION (Physical)
   0x05, 0x09,         //      USAGE_PAGE (Button)
   0x19, 0x01,         //      USAGE_MINIMUM (Button 1)
   0x29, 0x10,         //      USAGE_MAXIMUM (Button 16)
   0x15, 0x00,         //      LOGICAL_MINIMUM (0)
   0x25, 0x01,         //      LOGICAL_MAXIMUM (1)
   0x95, 0x10,         //      REPORT_COUNT (16)
   0x75, 0x01,         //      REPORT_SIZE (1)
   0x81, 0x02,         //      INPUT (Data,Var,Abs)
   0x05, 0x01,         //      USAGE_PAGE (Generic Desktop)
   0x09, 0x30,         //      USAGE (X)
   0x09, 0x31,         //      USAGE (Y)
   0x09, 0x32,         //      USAGE (Z)
   0x09, 0x33,         //      USAGE (Rx)
   0x09, 0x34,         //      USAGE (Ry)
   0x09, 0x35,         //      USAGE (Rz)
   0x15, 0x00,         //      LOGICAL_MINIMUM (0)
   0x26, 0xff, 0x00,   //      LOGICAL_MAXIMUM (255)
   0x95, 0x06,         //      REPORT_COUNT (6)
   0x75, 0x08,         //      REPORT_SIZE (8)
   0x81, 0x02,         //      INPUT (Data,Var,Abs)
   0xc0,            //   END_COLLECTION
   0xc0            // END_COLLECTION
};


And the structure that holds the values:

Code: Select all

typedef struct {
   uint16_t buttons;
   uint8_t x;
   uint8_t y;
   uint8_t z;
   uint8_t rx;
   uint8_t ry;
   uint8_t rz;
} gamepad_report_t;


If I change USAGE_MAXIMUM to 0x20 (Button 32), REPORT_COUNT to 0x20 (32) and the relevant part of the structure to uint32_t buttons like so...

Code: Select all

PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
0x05, 0x01,         // USAGE_PAGE (Generic Desktop)
0x09, 0x05,         // USAGE (Game Pad)
0xa1, 0x01,         // COLLECTION (Application)
0xa1, 0x00,         //   COLLECTION (Physical)
0x05, 0x09,         //      USAGE_PAGE (Button)
0x19, 0x01,         //      USAGE_MINIMUM (Button 1)
0x29, 0x20,         //      USAGE_MAXIMUM (Button 32)
0x15, 0x00,         //      LOGICAL_MINIMUM (0)
0x25, 0x01,         //      LOGICAL_MAXIMUM (1)
0x95, 0x20,         //      REPORT_COUNT (32)
0x75, 0x01,         //      REPORT_SIZE (1)
0x81, 0x02,         //      INPUT (Data,Var,Abs)
0x05, 0x01,         //      USAGE_PAGE (Generic Desktop)
0x09, 0x30,         //      USAGE (X)
0x09, 0x31,         //      USAGE (Y)
0x09, 0x32,         //      USAGE (Z)
0x09, 0x33,         //      USAGE (Rx)
0x09, 0x34,         //      USAGE (Ry)
0x09, 0x35,         //      USAGE (Rz)
0x15, 0x00,         //      LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00,   //      LOGICAL_MAXIMUM (255)
0x95, 0x06,         //      REPORT_COUNT (6)
0x75, 0x08,         //      REPORT_SIZE (8)
0x81, 0x02,         //      INPUT (Data,Var,Abs)
0xc0,            //   END_COLLECTION
0xc0            // END_COLLECTION
};

typedef struct {
   uint32_t buttons;
   uint8_t x;
   uint8_t y;
   uint8_t z;
   uint8_t rx;
   uint8_t ry;
   uint8_t rz;
} gamepad_report_t;


...then the device gets installed correctly and I can see all 32 buttons in the game controller setup dialog of windows, but it doesn't accept any inputs anymore. Not from any of the buttons, not from any of the axis.
I verified that the USB communication is indeed correct and the respective bits are set when I press buttons. I've debugged this for half a day now and I'm fairly confident that the code is correct.

Is there a hard limit of 16 digital buttons for gamepads?

I a related matter, does anyone have a working HIDreportDescriptor for a joystick? I know for a fact that those support more than 16 buttons ;)

Thanks in advance

Re: HID Gamepad - not more than 16 buttons?

Posted: Wed Sep 10, 2014 8:12 pm
by blargg
At first I thought it might be an issue with the report being longer than 8 bytes for a low-speed device, but when I pared it down to just buttons (so as to get the report <= 8 bytes), no matter what I did, going from 16 to 32 buttons caused it to not show up as /dev/input/js0 on Ubuntu 12.04. I tried making REPORT_COUNT 32 and REPORT_SIZE 1, and REPORT_COUNT 1 and REPORT_SIZE 32, etc. but it just doesn't like 32 buttons. My conclusion is that some other encoding is needed for 32 buttons (possibly anything more than 16 even).

...and indeed, when I changed the USAGE from a Game Pad (0x05) to a Joystick (0x04), it works and 32 buttons show up fine. At least Ubuntu 12.04 doesn't seem to support 32 buttons on a Game Pad, even though 16 work fine.

Going back to your original report, as described in an older posting, to use a report longer than 8 bytes, one must still make multiple calls to usbSetInterrupt() (a single did not work). This worked for me:

Code: Select all

while ( !usbInterruptIsReady() )
    usbPoll();
usbSetInterrupt( report, 8 );
while ( !usbInterruptIsReady() )
    usbPoll();
usbSetInterrupt( report + 8, sizeof report - 8 );


Is there a hard limit of 16 digital buttons for gamepads?

I a related matter, does anyone have a working HIDreportDescriptor for a joystick? I know for a fact that those support more than 16 buttons ;)


Oh, I guess you had already solved the problem the way I did, and I should have read your whole post carefully before embarking on my own research :)

Re: HID Gamepad - not more than 16 buttons?

Posted: Thu Sep 11, 2014 1:32 pm
by MrOnak
Thanks for the reply! Good to know that I don't have some brainfart regarding this issue.

I haven't solved the issue yet but it turns out that creating a device that registers itself as joystick (6 analog axis with 4 buttons) AND as keyboard is more flexible for what I want to do: That'd allow me to map the many buttons to actual keypresses, rather than relying on the receiving software (games mostly) being able to handle 30+ joystick buttons (some will, some won't). At the moment I have both reports working independently (seperate .hex files) but combining them into a single device causes Win to fail to register the device - more debugging :)

Thanks for the tip about sending multiple reports for > 8 byte, I didn't even think about that as an option. Definitely good to know.

Once the whole thing works I'll put up another community project.

Re: HID Gamepad - not more than 16 buttons?

Posted: Thu Sep 11, 2014 1:45 pm
by MrOnak
blargg wrote:Going back to your original report, as described in an older posting, to use a report longer than 8 bytes, one must still make multiple calls to usbSetInterrupt() (a single did not work).


Hmm... I read the linked thread (thanks for that) but could you maybe elaborate a litte? What's confusing me is that the keyboard report with added reportId byte is already longer than 8 bytes and it works with a single call to usbSetInterrupt().

Code: Select all

typedef struct {
    uint8_t report_id;
    uint8_t modifier;
    uint8_t reserved;
    uint8_t keycode[6];
} keyboard_report_t;


I'm obviously missing something here but right now these two things seem to contradict each other. Maybe I'm just lucky?

Re: HID Gamepad - not more than 16 buttons?

Posted: Thu Sep 11, 2014 8:17 pm
by blargg
Thanks for elaborating and reminding me that confirmation of issues is valuable too.

I wanted to figure out why there were separate classes for Game Pad and Joystick. I wasn't able to find out any more or a spec of each of their limitations.

I understood the longer report thing to basically be that you have to carefully always send groups of usbSetInterrupt() calls with the proper number of bytes, and manually keep track of which one is expected to have the beginning of the report. You say one worked without it; I wonder whether you can send a shorter report and the host treat the rest as zero. Then the last byte of your 9-byte packet might look like an all-zero first-8-bytes of it. To test this you could have a key always held in keycode[5] so that it might break things if it were treated as the report_id field.

Remember that >8 byte reports on low-speed USB double latency (>16 triple, etc.). I think that some people use multiple report IDs (as you mentioned) to reduce latency, at least in the case where only one report's inputs change in a given interrupt period.

I'll probably research more on the report_id, because I could use more understanding of it.

Re: HID Gamepad - not more than 16 buttons?

Posted: Fri Sep 12, 2014 4:13 pm
by ulao
I wanted to figure out why there were separate classes for Game Pad and Joystick.
Yeah I ran in to this as well. Joystick is mainly for flight application as it has ruder and throttle controls. The game pad is more for everything else. For example the PID layer will not work on the joystick only game pads so you can not have rumble with a joystick. It may be there just for some backward compatibility thing, not sure. Though never use joystick unless you need more flight friendly control names.

BTW: the issue with game pads seeing 32 buttons was a bug in the kernel. Its now fixed as I submitted the bug. kernel version released after 10/31/2012, which should be 3.8 or later has the fix.
http://comments.gmane.org/gmane.linux.k ... nput/27616

So Ubuntu 13.04 or later will see all 32.