12 POV hats for Extreme Joystick

Hello, I am interested in adding more POV hats to the "extreme joystick", it currently supports 4 and I would like it to support 12. I am using a teensy 4.0. As you can see below, I have removed 2 sliders which I do not need that take up 4 bytes and added 8 pov hats. I think that this descriptor should be correct? Although I have a feeling something is wrong.
Code:
// extreme joystick  (to use this, edit JOYSTICK_SIZE to 64 in usb_desc.h)
// In usb_desc.c
//  128 buttons   16
//    6 axes      12
//   15 sliders   30
//    12 pov        6
static uint8_t joystick_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x04,                     // Usage (Joystick)
        0xA1, 0x01,                     // Collection (Application)
        0x15, 0x00,                     // Logical Minimum (0)
        0x25, 0x01,                     // Logical Maximum (1)
        0x75, 0x01,                     // Report Size (1)
        0x95, 0x80,                     // Report Count (128)
        0x05, 0x09,                     // Usage Page (Button)
        0x19, 0x01,                     // Usage Minimum (Button #1)
        0x29, 0x80,                     // Usage Maximum (Button #128)
        0x81, 0x02,                     // Input (variable,absolute)
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x01,                     // Usage (Pointer)
        0xA1, 0x00,                     // Collection ()
        0x15, 0x00,                     // Logical Minimum (0)
        0x27, 0xFF, 0xFF, 0, 0,         // Logical Maximum (65535)
        0x75, 0x10,                     // Report Size (16)
        0x95, 23,                       // Report Count (23)
        0x09, 0x30,                     // Usage (X)
        0x09, 0x31,                     // Usage (Y)
        0x09, 0x32,                     // Usage (Z)
        0x09, 0x33,                     // Usage (Rx)
        0x09, 0x34,                     // Usage (Ry)
        0x09, 0x35,                     // Usage (Rz)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x81, 0x02,                     // Input (variable,absolute)
        0xC0,                           // End Collection
        0x15, 0x00,                     // Logical Minimum (0)
        0x25, 0x07,                     // Logical Maximum (7)
        0x35, 0x00,                     // Physical Minimum (0)
        0x46, 0x3B, 0x01,               // Physical Maximum (315)
        0x75, 0x04,                     // Report Size (4)
        0x95, 0xC,                     // Report Count (12)
        0x65, 0x14,                     // Unit (20)
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x81, 0x42,                     // Input (variable,absolute,null_state)
        0xC0                            // End Collection
};
#endif // JOYSTICK_SIZE
#endif // JOYSTICK_INTERFACE
I have also changed the hat function as follows but I am fairly sure that I have done something wrong. As I understand it usb_joystick_data is an array with 16 elements of 32 bits each. So in the hat function I (think) am using the first 16 bits of the 13th,14th and 15th set of 32 bits. This seems wrong but I am not sure how to structure it. Any advice at all would be apricated as there is a decent chance I am completely forgetting something I need to do.
Code:
//in usb_joystick.h 
inline void hat(unsigned int num, int angle) {
		uint32_t val=angle;
		uint32_t *p = usb_joystick_data;
		switch(num) {
		  case 1:
			p[13] = (p[13] & 0xFFF0FFFF) | (val << 16); break;
		  case 2:
			p[13] = (p[13] & 0xFF0FFFFF) | (val << 20); break;
		  case 3:
			p[13] = (p[13] & 0xF0FFFFFF) | (val << 24); break;
		  case 4:
			p[13] = (p[13] & 0x0FFFFFFF) | (val << 28); break;
		  case 5:
			p[14] = (p[14] & 0xFFF0FFFF) | (val << 16); break;
		  case 6:
			p[14] = (p[14] & 0xFF0FFFFF) | (val << 20); break;
		  case 7:
			p[14] = (p[14] & 0xF0FFFFFF) | (val << 24); break;
		  case 8:
			p[14] = (p[15] & 0x0FFFFFFF) | (val << 28); break;
		  case 9:
			p[15] = (p[15] & 0xFFF0FFFF) | (val << 16); break;
		  case 10:
			p[15] = (p[15] & 0xFF0FFFFF) | (val << 20); break;
		  case 11:
			p[15] = (p[15] & 0xF0FFFFFF) | (val << 24); break;
		  case 12:
			p[15] = (p[15] & 0x0FFFFFFF) | (val << 28); break;
		  default:
			return;
		}
		if (!manual_mode) usb_joystick_send();
        }
 
Last edited:
Sorry, I am probably missing some things, but for example I believe there may be some problems with your descriptor.

For example in this part of your descriptor:
Code:
        0xA1, 0x00,                     // Collection ()
        0x15, 0x00,                     // Logical Minimum (0)
        0x27, 0xFF, 0xFF, 0, 0,         // Logical Maximum (65535)
        0x75, 0x10,                     // Report Size (16)
       [COLOR="#FF0000"] 0x95, 23,                       // Report Count (23)[/COLOR]
        0x09, 0x30,                     // Usage (X)
        0x09, 0x31,                     // Usage (Y)
        0x09, 0x32,                     // Usage (Z)
        0x09, 0x33,                     // Usage (Rx)
        0x09, 0x34,                     // Usage (Ry)
        0x09, 0x35,                     // Usage (Rz)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
You dropped two slider objects.
So you probably need to update the count: Probably should be 21 not 23

I see that you updated the report count for the hats, so that part is probably good...

Also not sure about your hat function. Again I would need to figure out where your data fits... But looking at the the code in teensyduino I see:
Code:
		uint32_t *p = usb_joystick_data;
		switch(num) {
		  case 1:
			p[15] = (p[15] & 0xFFF0FFFF) | (val << 16); break;
		  case 2:
			p[15] = (p[15] & 0xFF0FFFFF) | (val << 20); break;
		  case 3:
			p[15] = (p[15] & 0xF0FFFFFF) | (val << 24); break;
		  case 4:
			p[15] = (p[15] & 0x0FFFFFFF) | (val << 28); break;
		  default:
			return;
		}
So you removed Two sliders, or 32 bits so would expect it to start with p[14] not p[13].
Also they skip the lower word as I am assuming that is the alignment for the last slider.

But once you finish those first 4 the next one should start off in the first nibble of P15


Code:
		  case 1:
			p[14] = (p[14] & 0xFFF0FFFF) | (val << 16); break;
		  case 2:
			p[14] = (p[14] & 0xFF0FFFFF) | (val << 20); break;
		  case 3:
			p[14] = (p[14] & 0xF0FFFFFF) | (val << 24); break;
		  case 4:
			p[14] = (p[14] & 0x0FFFFFFF) | (val << 28); break;

		  case 5:
			p[15] = (p[15] & 0xFFFFFFF0) | (val << 0); break;
		  case 6:
			p[15] = (p[15] & 0xFFFFFF0F) | (val << 4); break;
...
		  case 12:
			p[15] = (p[15] & 0x0FFFFFFF) | (val << 28); break;
		  default:
			return;
But I could be completely wrong
 
Thanks for the help, made the changes you suggested and now it seems to be partially working. By partially I mean that it appears the last 4 cases (9-12) work as hat switches while the remainder do nothing so I think there must be something else I am missing. I am not totally sure what it means but both jstest-gtk, and joy.cpl both do not display any axis when I use them. joycpl.png I am not sure if this is because there is keyboard and mouse output as well but was just something I thought could be relevant. What software is used when testing joysticks with uncommon amounts of hats/axis/sliders? The full code for my project is below. The idea is to read in an input from a controller, then use the emulated joystick to pass back the values through POV hat values (I know it sounds insane but don't worry about it). If you or anyone else has ideas about how to get these hat switches working they would be most welcome.
Code:
// Simple test of USB Host Joystick
//
// This example is in the public domain

// Joystick host code start
#include "USBHost_t36.h"
USBHost myusb;
USBHub hub1(myusb);
USBHIDParser hid1(myusb);

#define COUNT_JOYSTICKS 4
JoystickController joysticks[COUNT_JOYSTICKS](myusb);
int user_axis[64];
uint32_t buttons_prev = 0;

USBDriver *drivers[] = {&hub1, &joysticks[0], &joysticks[1], &joysticks[2], &joysticks[3], &hid1};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1", "joystick[0D]", "joystick[1D]", "joystick[2D]", "joystick[3D]",  "HID1"};
bool driver_active[CNT_DEVICES] = {false, false, false, false};

// Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&joysticks[0], &joysticks[1], &joysticks[2], &joysticks[3]};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"joystick[0H]", "joystick[1H]", "joystick[2H]", "joystick[3H]"};
bool hid_driver_active[CNT_DEVICES] = {false};
bool show_changed_only = false;

uint8_t joystick_left_trigger_value[COUNT_JOYSTICKS] = {0};
uint8_t joystick_right_trigger_value[COUNT_JOYSTICKS] = {0};
uint64_t joystick_full_notify_mask = (uint64_t) - 1;

int psAxis[64];
// Joystick host code end

// Controller Emulator code start

// Configure the number of buttons.  Be careful not
// to use a pin for both a digital button and analog
// axis.  The pullup resistor will interfere with
// the analog voltage.
const int numButtons = 16;
byte allButtons[numButtons];
byte prevButtons[numButtons];
int angle=0;
// Controller Emulator code end

//=============================================================================
// Setup
//=============================================================================
void setup()
{
  Serial1.begin(2000000);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("\n\nUSB Host Joystick Testing");
  myusb.begin();

  // Emulator code
  Serial.begin(9600);
  Joystick.useManualSend(true);
  for (int i=0; i<numButtons; i++) {
    pinMode(i, INPUT_PULLUP);
  }
   Serial.println("Begin Complete Joystick Test");
}


//=============================================================================
// loop
//=============================================================================
void loop()
{
  myusb.Task();
  PrintDeviceListChanges();
  //printAxis();

  // signed 16 bit integers
  int16_t  lftx = joysticks[0].getAxis(0);
  int16_t  lfty = joysticks[0].getAxis(1);
  int16_t  rhtx = joysticks[0].getAxis(2);
  int16_t  rhty = joysticks[0].getAxis(5);
  Serial.printf("Left stick left right:  %d\n", lftx);
  Serial.println((lftx & 0xF) >> 0);
  Serial.println((lftx & 0xF0) >> 4);
  Serial.println((lftx & 0xF00) >> 8);
  Serial.println((lftx & 0xF000) >> 12);
   
  // Hats 1-4 represent left stick X
  // First 4, then next 4, etc
  
  
  Joystick.hat(1, (lftx & 0xF000) >> 12);
  Joystick.hat(2, (lftx & 0xF00) >> 8);
  Joystick.hat(3, (lftx & 0xF0) >> 4);
  Joystick.hat(4, (lftx & 0xF) >> 0);
  
  
  // 5-8 left stick Y
  Joystick.hat(5, (lfty & 0xF000) >> 12);
  Joystick.hat(6, (lfty & 0xF00) >> 8);
  Joystick.hat(7, (lfty & 0xF0) >> 4);
  Joystick.hat(8, (lfty & 0xF) >> 0);
  // 9-12 right stick X
  // right stick Y ignored becuase we don't use it and driver's station only allows 12 hats
  Joystick.hat(9, (rhtx & 0xF000) >> 12);
  Joystick.hat(10, (rhtx & 0xF00) >> 8);
  Joystick.hat(11, (rhtx & 0xF0) >> 4);
  Joystick.hat(12, (rhtx & 0xF) >> 0);

  Joystick.X(600);
  Joystick.Y(1023);
  Joystick.Z(194); 
  
  // DO NOT FORGET THIS
  Joystick.send_now();
  joysticks[0].joystickDataClear();
}
  
void printAxis()
{
  if (joysticks[0].available()) {
    
    int16_t lftx = joysticks[0].getAxis(0);
    int16_t lfty = joysticks[0].getAxis(1);
    int16_t rhtx = joysticks[0].getAxis(2);
    int16_t rhty = joysticks[0].getAxis(5);
    /*
    Serial.printf("Left stick up down:  %d", lftud);
    Serial.println();
    Serial.printf("Left stick left right:  %d", lftlr);
    Serial.println();/-32,768
    
    Serial.printf("Right stick up down:  %d", rhtud);
    Serial.println();
    Serial.printf("Right stick left right:  %d", rhtlr);
    Serial.println();
    */
    Serial.printf("Left stick left right:  %d\n", lftx);
    Serial.println((lftx & 0xF));
    Serial.println((lftx & 0xF0) >> 4);
    Serial.println((lftx & 0xF00) >> 8);
    Serial.println((lftx & 0xF000) >> 12);
  } 
 }

//=============================================================================
// Show when devices are added or removed
//=============================================================================
void PrintDeviceListChanges() {
  for (uint8_t i = 0; i < CNT_DEVICES; i++) {
    if (*drivers[i] != driver_active[i]) {
      if (driver_active[i]) {
        Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]);
        driver_active[i] = false;
      } else {
        Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
        driver_active[i] = true;

        const uint8_t *psz = drivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = drivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = drivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);
      }
    }
  }

  for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) {
    if (*hiddrivers[i] != hid_driver_active[i]) {
      if (hid_driver_active[i]) {
        Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]);
        hid_driver_active[i] = false;
      } else {
        Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
        hid_driver_active[i] = true;

        const uint8_t *psz = hiddrivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = hiddrivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = hiddrivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);
      }
    }
  }
}
New descriptor
Code:
#elif JOYSTICK_SIZE == 64
// extreme joystick  (to use this, edit JOYSTICK_SIZE to 64 in usb_desc.h)
//  128 buttons   16
//    6 axes      12
//   15 sliders   30
//    12 pov       6
static uint8_t joystick_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x04,                     // Usage (Joystick)
        0xA1, 0x01,                     // Collection (Application)
        0x15, 0x00,                     // Logical Minimum (0)
        0x25, 0x01,                     // Logical Maximum (1)
        0x75, 0x01,                     // Report Size (1)
        0x95, 0x80,                     // Report Count (128)
        0x05, 0x09,                     // Usage Page (Button)
        0x19, 0x01,                     // Usage Minimum (Button #1)
        0x29, 0x80,                     // Usage Maximum (Button #128)
        0x81, 0x02,                     // Input (variable,absolute)
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x01,                     // Usage (Pointer)
        0xA1, 0x00,                     // Collection ()
        0x15, 0x00,                     // Logical Minimum (0)
        0x27, 0xFF, 0xFF, 0, 0,         // Logical Maximum (65535)
        0x75, 0x10,                     // Report Size (16)
        0x95, 21,                     // Report Count (21)
        0x09, 0x30,                     // Usage (X)
        0x09, 0x31,                     // Usage (Y)
        0x09, 0x32,                     // Usage (Z)
        0x09, 0x33,                     // Usage (Rx)
        0x09, 0x34,                     // Usage (Ry)
        0x09, 0x35,                     // Usage (Rz)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x09, 0x36,                     // Usage (Slider)
        0x81, 0x02,                     // Input (variable,absolute)
        0xC0,                           // End Collection
        0x15, 0x00,                     // Logical Minimum (0)
        0x25, 0x07,                     // Logical Maximum (7)
        0x35, 0x00,                     // Physical Minimum (0)
        0x46, 0x3B, 0x01,               // Physical Maximum (315)
        0x75, 0x04,                     // Report Size (4)
        0x95, 0xC,                      // Report Count (12)
        0x65, 0x14,                     // Unit (20)
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x09, 0x39,                     // Usage (Hat switch)
        0x81, 0x42,                     // Input (variable,absolute,null_state)
        0xC0                            // End Collection

};
 
If it were me, I would probably double check using 2nd Teensy. Like I show here...

I did a little playing:
I did not edit your last usb_desc.c file
I did edit usb_desc.h to make sure the 64 byte version was selected.

I changed usb_joystick.h to
Code:
#elif JOYSTICK_SIZE == 64
	void button(unsigned int num, bool val) {
		if (--num >= 128) return;
		uint32_t *p = usb_joystick_data + (num >> 5);
		num &= 0x1F;
		if (val) *p |= (1 << num);
		else *p &= ~(1 << num);
		if (!manual_mode) usb_joystick_send();
	}
	void X(unsigned int position) { analog16(0, position); }
	void Y(unsigned int position) { analog16(1, position); }
	void Z(unsigned int position) { analog16(2, position); }
	void Xrotate(unsigned int position) { analog16(3, position); }
	void Yrotate(unsigned int position) { analog16(4, position); }
	void Zrotate(unsigned int position) { analog16(5, position); }
	void slider(unsigned int num, unsigned int position) {
		if (--num >= 15) return;
		analog16(num + 6, position);
	}
        inline void hat(unsigned int num, int angle) {
		uint32_t val=15;
		if (angle > 0 && angle < 23) val = 0;
		else if (angle < 68) val = 1;
		else if (angle < 113) val = 2;
		else if (angle < 158) val = 3;
		else if (angle < 203) val = 4;
		else if (angle < 245) val = 5;
		else if (angle < 293) val = 6;
		else if (angle < 338) val = 7;
		else if (angle < 360) val = 0;
		uint32_t *p = usb_joystick_data;
		switch(num) {
		  case 1:
			p[14] = (p[14] & 0xFFF0FFFF) | (val << 16); break;
		  case 2:
			p[14] = (p[14] & 0xFF0FFFFF) | (val << 20); break;
		  case 3:
			p[14] = (p[14] & 0xF0FFFFFF) | (val << 24); break;
		  case 4:
			p[14] = (p[14] & 0x0FFFFFFF) | (val << 28); break;
	  	  case 5: p[15] =  (p[15] & 0xFFFFFFF0) | (val << 0); break;
		  case 6: p[15] =  (p[15] & 0xFFFFFF0F) | (val << 4); break;
		  case 7: p[15] =  (p[15] & 0xFFFFF0FF) | (val << 8); break;
		  case 8: p[15] =  (p[15] & 0xFFFF0FFF) | (val << 12); break;
		  case 9: p[15] =  (p[15] & 0xFFF0FFFF) | (val << 16); break;
		  case 10: p[15] = (p[15] & 0xFF0FFFFF) | (val << 20); break;
		  case 11: p[15] = (p[15] & 0xF0FFFFFF) | (val << 24); break;
		  case 12: p[15] = (p[15] & 0x0FFFFFFF) | (val << 28); break;
		  default:
			return;
		}
		if (!manual_mode) usb_joystick_send();
        }

Real simple test program
Code:
/* Complete USB Joystick Example
   Teensy becomes a USB joystick with 16 or 32 buttons and 6 axis input

   You must select Joystick from the "Tools > USB Type" menu

   Pushbuttons should be connected between the digital pins and ground.
   Potentiometers should be connected to analog inputs 0 to 5.

   This example code is in the public domain.
*/


void setup() {
  // you can print to the serial monitor while the joystick is active!
  Serial.begin(9600);
  Joystick.useManualSend(true);
  Serial.println("Begin Complete Joystick Test");
}


uint16_t loop_count = 0;
void loop() {
  loop_count++;
  // read 6 analog inputs and use them for the joystick axis
  Joystick.X(loop_count);
  Joystick.Y(loop_count + 1);
  Joystick.Z(loop_count + 2);
  Joystick.Xrotate(loop_count + 3);
  Joystick.Yrotate(loop_count + 4);
  Joystick.Zrotate(loop_count + 5);
  for (uint8_t i = 1; i < 15; i++) Joystick.slider(i, loop_count + 0x1000 + i);
  for (uint8_t i = 1; i < 13; i++) Joystick.hat(i, ((loop_count + i) & 7) * 45);
  for (uint8_t i = 1; i < 129; i++) Joystick.button(i, (loop_count + i) & 1);
  Joystick.send_now();

  // a brief delay, so this runs "only" 200 times per second
  delay(50);
}

EDIT: on main computer
Now on my main Windows 10 machine, I used a second teensy, in this case a MicroMod that has USB Host port on it.
So I programmed the MicroMod with the USBHost_t36 example sketch HiDDeviceInfo

Test run:
Code:
USBDeviceInfo claim this=2000BAC4

****************************************
** Device Level **
  vid=16C0
  pid=487
  bDeviceClass = 239
  bDeviceSubClass = 2
  bDeviceProtocol = 1
08 0B 00 02 02 02 01 00 09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05
24 06 00 01 07 05 82 03 10 00 05 09 04 01 00 02 0A 00 00 00 07 05 03 02 00 02 00 07 05 83 02 00
02 00 09 04 02 00 01 03 01 01 00 09 21 11 01 00 01 22 3F 00 07 05 84 03 08 00 01 09 04 03 00 01
03 00 00 00 09 21 11 01 00 01 22 54 00 07 05 86 03 08 00 02 09 04 04 00 01 03 00 00 00 09 21 11
01 00 01 22 86 00 07 05 87 03 40 00 01 09 04 05 00 01 03 00 00 00 09 21 11 01 00 01 22 28 00 07
05 85 03 08 00 04 

USBDeviceInfo claim this=2000BAC4

****************************************
** Interface Level **
09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05 24 06 00 01 07 05 82 03
10 00 05 09 04 01 00 02 0A 00 00 00 07 05 03 02 00 02 00 07 05 83 02 00 02 00 09 04 02 00 01 03
01 01 00 09 21 11 01 00 01 22 3F 00 07 05 84 03 08 00 01 09 04 03 00 01 03 00 00 00 09 21 11 01
00 01 22 54 00 07 05 86 03 08 00 02 09 04 04 00 01 03 00 00 00 09 21 11 01 00 01 22 86 00 07 05
87 03 40 00 01 09 04 05 00 01 03 00 00 00 09 21 11 01 00 01 22 28 00 07 05 85 03 08 00 04 
 bInterfaceNumber = 0
 number end points = 1
 bInterfaceClass =    2
 bInterfaceSubClass = 2
    Communicatons and CDC
 bInterfaceProtocol = 1

USBDeviceInfo claim this=2000BAC4

****************************************
** Interface Level **
09 04 01 00 02 0A 00 00 00 07 05 03 02 00 02 00 07 05 83 02 00 02 00 09 04 02 00 01 03 01 01 00
09 21 11 01 00 01 22 3F 00 07 05 84 03 08 00 01 09 04 03 00 01 03 00 00 00 09 21 11 01 00 01 22
54 00 07 05 86 03 08 00 02 09 04 04 00 01 03 00 00 00 09 21 11 01 00 01 22 86 00 07 05 87 03 40
00 01 09 04 05 00 01 03 00 00 00 09 21 11 01 00 01 22 28 00 07 05 85 03 08 00 04 
 bInterfaceNumber = 1
 number end points = 2
 bInterfaceClass =    10
 bInterfaceSubClass = 0
    CDC-Data
 bInterfaceProtocol = 0

USBDeviceInfo claim this=2000BAC4

****************************************
** Interface Level **
09 04 02 00 01 03 01 01 00 09 21 11 01 00 01 22 3F 00 07 05 84 03 08 00 01 09 04 03 00 01 03 00
00 00 09 21 11 01 00 01 22 54 00 07 05 86 03 08 00 02 09 04 04 00 01 03 00 00 00 09 21 11 01 00
01 22 86 00 07 05 87 03 40 00 01 09 04 05 00 01 03 00 00 00 09 21 11 01 00 01 22 28 00 07 05 85
03 08 00 04 
 bInterfaceNumber = 2
 number end points = 1
 bInterfaceClass =    3
 bInterfaceSubClass = 1
    HID (BOOT)
 bInterfaceProtocol = 1
report descriptor size = 63
  endpoint = 84
    attributes = 3 Interrupt
    size = 8
    interval = 1
*** Device HID1 16c0: 487 - connected ***
  manufacturer: Teensyduino
  product: Serial/Keyboard/Mouse/Joystick
  Serial: 108835
*** Device HID2 16c0: 487 - connected ***
  manufacturer: Teensyduino
  product: Serial/Keyboard/Mouse/Joystick
  Serial: 108835
*** Device HID3 16c0: 487 - connected ***
  manufacturer: Teensyduino
  product: Serial/Keyboard/Mouse/Joystick
  Serial: 108835
HIDDumpController Claim: 16c0:487 usage: 10002 - Yes
HIDDumpController Claim: 16c0:487 usage: 10002 - Yes
HIDDumpController Claim: 16c0:487 usage: 10004 - NO (Usage: 402e0000)
HIDDumpController Claim: 16c0:487 usage: 10004 - Yes
HIDDumpController Claim: 16c0:487 usage: c0001 - NO (Usage: 402e0000)
HIDDumpController Claim: 16c0:487 usage: c0001 - NO (Usage: 402e0000)
HIDDumpController Claim: 16c0:487 usage: c0001 - Yes
*** HID Device hdc2 16c0: 487 - connected ***
  manufacturer: Teensyduino
  product: Serial/Keyboard/Mouse/Joystick
  Serial: 108835
*** HID Device hdc3 16c0: 487 - connected ***
  manufacturer: Teensyduino
  product: Serial/Keyboard/Mouse/Joystick
  Serial: 108835
*** HID Device hdc1 16c0: 487 - connected ***
  manufacturer: Teensyduino
  product: Serial/Keyboard/Mouse/Joystick
  Serial: 108835
HID(10004): AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 01 00 02 00 03 00 04 00 05 00 06 00 02 10 03 10
04 10 05 10 06 10 07 10 08 10 09 10 0A 10 0B 10 0C 10 0D 10 0E 10 0F 10 00 00 32 54 76 11 32 54 
Begin topusage:10000 type:2 min:0 max:1
  usage=90001, value=0 (BUTTON 1)
  usage=90002, value=1 (BUTTON 2)
  usage=90003, value=0 (BUTTON 3)
  usage=90004, value=1 (BUTTON 4)
  usage=90005, value=0 (BUTTON 5)
  usage=90006, value=1 (BUTTON 6)
  usage=90007, value=0 (BUTTON 7)
  usage=90008, value=1 (BUTTON 8)
  usage=90009, value=0 (BUTTON 9)
  usage=9000A, value=1 (BUTTON 10)
  usage=9000B, value=0 (BUTTON 11)
  usage=9000C, value=1 (BUTTON 12)
  usage=9000D, value=0 (BUTTON 13)
  usage=9000E, value=1 (BUTTON 14)
  usage=9000F, value=0 (BUTTON 15)
  usage=90010, value=1 (BUTTON 16)
  usage=90011, value=0 (BUTTON 17)
  usage=90012, value=1 (BUTTON 18)
  usage=90013, value=0 (BUTTON 19)
  usage=90014, value=1 (BUTTON 20)
  usage=90015, value=0 (BUTTON 21)
  usage=90016, value=1 (BUTTON 22)
  usage=90017, value=0 (BUTTON 23)
  usage=90018, value=1 (BUTTON 24)
  usage=90019, value=0 (BUTTON 25)
  usage=9001A, value=1 (BUTTON 26)
  usage=9001B, value=0 (BUTTON 27)
  usage=9001C, value=1 (BUTTON 28)
  usage=9001D, value=0 (BUTTON 29)
  usage=9001E, value=1 (BUTTON 30)
  usage=9001F, value=0 (BUTTON 31)
  usage=90020, value=1 (BUTTON 32)
  usage=90021, value=0 (BUTTON 33)
  usage=90022, value=1 (BUTTON 34)
  usage=90023, value=0 (BUTTON 35)
  usage=90024, value=1 (BUTTON 36)
  usage=90025, value=0 (BUTTON 37)
  usage=90026, value=1 (BUTTON 38)
  usage=90027, value=0 (BUTTON 39)
  usage=90028, value=1 (BUTTON 40)
  usage=90029, value=0 (BUTTON 41)
  usage=9002A, value=1 (BUTTON 42)
  usage=9002B, value=0 (BUTTON 43)
  usage=9002C, value=1 (BUTTON 44)
  usage=9002D, value=0 (BUTTON 45)
  usage=9002E, value=1 (BUTTON 46)
  usage=9002F, value=0 (BUTTON 47)
  usage=90030, value=1 (BUTTON 48)
  usage=90031, value=0 (BUTTON 49)
  usage=90032, value=1 (BUTTON 50)
  usage=90033, value=0 (BUTTON 51)
  usage=90034, value=1 (BUTTON 52)
  usage=90035, value=0 (BUTTON 53)
  usage=90036, value=1 (BUTTON 54)
  usage=90037, value=0 (BUTTON 55)
  usage=90038, value=1 (BUTTON 56)
  usage=90039, value=0 (BUTTON 57)
  usage=9003A, value=1 (BUTTON 58)
  usage=9003B, value=0 (BUTTON 59)
  usage=9003C, value=1 (BUTTON 60)
  usage=9003D, value=0 (BUTTON 61)
  usage=9003E, value=1 (BUTTON 62)
  usage=9003F, value=0 (BUTTON 63)
  usage=90040, value=1 (BUTTON 64)
  usage=90041, value=0 (BUTTON 65)
  usage=90042, value=1 (BUTTON 66)
  usage=90043, value=0 (BUTTON 67)
  usage=90044, value=1 (BUTTON 68)
  usage=90045, value=0 (BUTTON 69)
  usage=90046, value=1 (BUTTON 70)
  usage=90047, value=0 (BUTTON 71)
  usage=90048, value=1 (BUTTON 72)
  usage=90049, value=0 (BUTTON 73)
  usage=9004A, value=1 (BUTTON 74)
  usage=9004B, value=0 (BUTTON 75)
  usage=9004C, value=1 (BUTTON 76)
  usage=9004D, value=0 (BUTTON 77)
  usage=9004E, value=1 (BUTTON 78)
  usage=9004F, value=0 (BUTTON 79)
  usage=90050, value=1 (BUTTON 80)
  usage=90051, value=0 (BUTTON 81)
  usage=90052, value=1 (BUTTON 82)
  usage=90053, value=0 (BUTTON 83)
  usage=90054, value=1 (BUTTON 84)
  usage=90055, value=0 (BUTTON 85)
  usage=90056, value=1 (BUTTON 86)
  usage=90057, value=0 (BUTTON 87)
  usage=90058, value=1 (BUTTON 88)
  usage=90059, value=0 (BUTTON 89)
  usage=9005A, value=1 (BUTTON 90)
  usage=9005B, value=0 (BUTTON 91)
  usage=9005C, value=1 (BUTTON 92)
  usage=9005D, value=0 (BUTTON 93)
  usage=9005E, value=1 (BUTTON 94)
  usage=9005F, value=0 (BUTTON 95)
  usage=90060, value=1 (BUTTON 96)
  usage=90061, value=0 (BUTTON 97)
  usage=90062, value=1 (BUTTON 98)
  usage=90063, value=0 (BUTTON 99)
  usage=90064, value=1 (BUTTON 100)
  usage=90065, value=0 (BUTTON 101)
  usage=90066, value=1 (BUTTON 102)
  usage=90067, value=0 (BUTTON 103)
  usage=90068, value=1 (BUTTON 104)
  usage=90069, value=0 (BUTTON 105)
  usage=9006A, value=1 (BUTTON 106)
  usage=9006B, value=0 (BUTTON 107)
  usage=9006C, value=1 (BUTTON 108)
  usage=9006D, value=0 (BUTTON 109)
  usage=9006E, value=1 (BUTTON 110)
  usage=9006F, value=0 (BUTTON 111)
  usage=90070, value=1 (BUTTON 112)
  usage=90071, value=0 (BUTTON 113)
  usage=90072, value=1 (BUTTON 114)
  usage=90073, value=0 (BUTTON 115)
  usage=90074, value=1 (BUTTON 116)
  usage=90075, value=0 (BUTTON 117)
  usage=90076, value=1 (BUTTON 118)
  usage=90077, value=0 (BUTTON 119)
  usage=90078, value=1 (BUTTON 120)
  usage=90079, value=0 (BUTTON 121)
  usage=9007A, value=1 (BUTTON 122)
  usage=9007B, value=0 (BUTTON 123)
  usage=9007C, value=1 (BUTTON 124)
  usage=9007D, value=0 (BUTTON 125)
  usage=9007E, value=1 (BUTTON 126)
  usage=9007F, value=0 (BUTTON 127)
  usage=90080, value=1 (BUTTON 128)
  Begin topusage:10000 type:2 min:0 max:65535
    usage=10030, value=1(X)
    usage=10031, value=2(Y)
    usage=10032, value=3(Z)
    usage=10033, value=4(Rx)
    usage=10034, value=5(Ry)
    usage=10035, value=6(Rz)
    usage=10036, value=4098(Slider)
    usage=10036, value=4099(Slider)
    usage=10036, value=4100(Slider)
    usage=10036, value=4101(Slider)
    usage=10036, value=4102(Slider)
    usage=10036, value=4103(Slider)
    usage=10036, value=4104(Slider)
    usage=10036, value=4105(Slider)
    usage=10036, value=4106(Slider)
    usage=10036, value=4107(Slider)
    usage=10036, value=4108(Slider)
    usage=10036, value=4109(Slider)
    usage=10036, value=4110(Slider)
    usage=10036, value=4111(Slider)
    usage=10036, value=0(Slider)
    Begin topusage:10000 type:42 min:0 max:7
    usage=10039, value=2(Hat)
    usage=10039, value=3(Hat)
    usage=10039, value=4(Hat)
    usage=10039, value=5(Hat)
    usage=10039, value=6(Hat)
    usage=10039, value=7(Hat)
    usage=10039, value=1(Hat)
    usage=10039, value=1(Hat)
    usage=10039, value=2(Hat)
    usage=10039, value=3(Hat)
    usage=10039, value=4(Hat)
    usage=10039, value=5(Hat)
  END:
HID(10004): 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 02 00 03 00 04 00 05 00 06 00 07 00 03 10 04 10
05 10 06 10 07 10 08 10 09 10 0A 10 0B 10 0C 10 0D 10 0E 10 0F 10 10 10 00 00 43 65 17 21 43 65 
Begin topusage:10000 type:2 min:0 max:1
  usage=90001, value=1 (BUTTON 1)
  usage=90002, value=0 (BUTTON 2)
  usage=90003, value=1 (BUTTON 3)
  usage=90004, value=0 (BUTTON 4)
  usage=90005, value=1 (BUTTON 5)
  usage=90006, value=0 (BUTTON 6)
  usage=90007, value=1 (BUTTON 7)
  usage=90008, value=0 (BUTTON 8)
  usage=90009, value=1 (BUTTON 9)
  usage=9000A, value=0 (BUTTON 10)
  usage=9000B, value=1 (BUTTON 11)
  usage=9000C, value=0 (BUTTON 12)
  usage=9000D, value=1 (BUTTON 13)
  usage=9000E, value=0 (BUTTON 14)
  usage=9000F, value=1 (BUTTON 15)
  usage=90010, value=0 (BUTTON 16)
  usage=90011, value=1 (BUTTON 17)
  usage=90012, value=0 (BUTTON 18)
  usage=90013, value=1 (BUTTON 19)
  usage=90014, value=0 (BUTTON 20)
  usage=90015, value=1 (BUTTON 21)
  usage=90016, value=0 (BUTTON 22)
  usage=90017, value=1 (BUTTON 23)
  usage=90018, value=0 (BUTTON 24)
  usage=90019, value=1 (BUTTON 25)
  usage=9001A, value=0 (BUTTON 26)
  usage=9001B, value=1 (BUTTON 27)
  usage=9001C, value=0 (BUTTON 28)
  usage=9001D, value=1 (BUTTON 29)
  usage=9001E, value=0 (BUTTON 30)
  usage=9001F, value=1 (BUTTON 31)
  usage=90020, value=0 (BUTTON 32)
  usage=90021, value=1 (BUTTON 33)
  usage=90022, value=0 (BUTTON 34)
  usage=90023, value=1 (BUTTON 35)
  usage=90024, value=0 (BUTTON 36)
  usage=90025, value=1 (BUTTON 37)
  usage=90026, value=0 (BUTTON 38)
  usage=90027, value=1 (BUTTON 39)
  usage=90028, value=0 (BUTTON 40)
  usage=90029, value=1 (BUTTON 41)
  usage=9002A, value=0 (BUTTON 42)
  usage=9002B, value=1 (BUTTON 43)
  usage=9002C, value=0 (BUTTON 44)
  usage=9002D, value=1 (BUTTON 45)
  usage=9002E, value=0 (BUTTON 46)
  usage=9002F, value=1 (BUTTON 47)
  usage=90030, value=0 (BUTTON 48)
  usage=90031, value=1 (BUTTON 49)
  usage=90032, value=0 (BUTTON 50)
  usage=90033, value=1 (BUTTON 51)
  usage=90034, value=0 (BUTTON 52)
  usage=90035, value=1 (BUTTON 53)
  usage=90036, value=0 (BUTTON 54)
  usage=90037, value=1 (BUTTON 55)
  usage=90038, value=0 (BUTTON 56)
  usage=90039, value=1 (BUTTON 57)
  usage=9003A, value=0 (BUTTON 58)
  usage=9003B, value=1 (BUTTON 59)
  usage=9003C, value=0 (BUTTON 60)
  usage=9003D, value=1 (BUTTON 61)
  usage=9003E, value=0 (BUTTON 62)
  usage=9003F, value=1 (BUTTON 63)
  usage=90040, value=0 (BUTTON 64)
  usage=90041, value=1 (BUTTON 65)
  usage=90042, value=0 (BUTTON 66)
  usage=90043, value=1 (BUTTON 67)
  usage=90044, value=0 (BUTTON 68)
  usage=90045, value=1 (BUTTON 69)
  usage=90046, value=0 (BUTTON 70)
  usage=90047, value=1 (BUTTON 71)
  usage=90048, value=0 (BUTTON 72)
  usage=90049, value=1 (BUTTON 73)
  usage=9004A, value=0 (BUTTON 74)
  usage=9004B, value=1 (BUTTON 75)
  usage=9004C, value=0 (BUTTON 76)
  usage=9004D, value=1 (BUTTON 77)
  usage=9004E, value=0 (BUTTON 78)
  usage=9004F, value=1 (BUTTON 79)
  usage=90050, value=0 (BUTTON 80)
  usage=90051, value=1 (BUTTON 81)
  usage=90052, value=0 (BUTTON 82)
  usage=90053, value=1 (BUTTON 83)
  usage=90054, value=0 (BUTTON 84)
  usage=90055, value=1 (BUTTON 85)
  usage=90056, value=0 (BUTTON 86)
  usage=90057, value=1 (BUTTON 87)
  usage=90058, value=0 (BUTTON 88)
  usage=90059, value=1 (BUTTON 89)
  usage=9005A, value=0 (BUTTON 90)
  usage=9005B, value=1 (BUTTON 91)
  usage=9005C, value=0 (BUTTON 92)
  usage=9005D, value=1 (BUTTON 93)
  usage=9005E, value=0 (BUTTON 94)
  usage=9005F, value=1 (BUTTON 95)
  usage=90060, value=0 (BUTTON 96)
  usage=90061, value=1 (BUTTON 97)
  usage=90062, value=0 (BUTTON 98)
  usage=90063, value=1 (BUTTON 99)
  usage=90064, value=0 (BUTTON 100)
  usage=90065, value=1 (BUTTON 101)
  usage=90066, value=0 (BUTTON 102)
  usage=90067, value=1 (BUTTON 103)
  usage=90068, value=0 (BUTTON 104)
  usage=90069, value=1 (BUTTON 105)
  usage=9006A, value=0 (BUTTON 106)
  usage=9006B, value=1 (BUTTON 107)
  usage=9006C, value=0 (BUTTON 108)
  usage=9006D, value=1 (BUTTON 109)
  usage=9006E, value=0 (BUTTON 110)
  usage=9006F, value=1 (BUTTON 111)
  usage=90070, value=0 (BUTTON 112)
  usage=90071, value=1 (BUTTON 113)
  usage=90072, value=0 (BUTTON 114)
  usage=90073, value=1 (BUTTON 115)
  usage=90074, value=0 (BUTTON 116)
  usage=90075, value=1 (BUTTON 117)
  usage=90076, value=0 (BUTTON 118)
  usage=90077, value=1 (BUTTON 119)
  usage=90078, value=0 (BUTTON 120)
  usage=90079, value=1 (BUTTON 121)
  usage=9007A, value=0 (BUTTON 122)
  usage=9007B, value=1 (BUTTON 123)
  usage=9007C, value=0 (BUTTON 124)
  usage=9007D, value=1 (BUTTON 125)
  usage=9007E, value=0 (BUTTON 126)
  usage=9007F, value=1 (BUTTON 127)
  usage=90080, value=0 (BUTTON 128)
  Begin topusage:10000 type:2 min:0 max:65535
    usage=10030, value=2(X)
    usage=10031, value=3(Y)
    usage=10032, value=4(Z)
    usage=10033, value=5(Rx)
    usage=10034, value=6(Ry)
    usage=10035, value=7(Rz)
    usage=10036, value=4099(Slider)
    usage=10036, value=4100(Slider)
    usage=10036, value=4101(Slider)
    usage=10036, value=4102(Slider)
    usage=10036, value=4103(Slider)
    usage=10036, value=4104(Slider)
    usage=10036, value=4105(Slider)
    usage=10036, value=4106(Slider)
    usage=10036, value=4107(Slider)
    usage=10036, value=4108(Slider)
    usage=10036, value=4109(Slider)
    usage=10036, value=4110(Slider)
    usage=10036, value=4111(Slider)
    usage=10036, value=4112(Slider)
    usage=10036, value=0(Slider)
    Begin topusage:10000 type:42 min:0 max:7
    usage=10039, value=3(Hat)
    usage=10039, value=4(Hat)
    usage=10039, value=5(Hat)
    usage=10039, value=6(Hat)
    usage=10039, value=7(Hat)
    usage=10039, value=1(Hat)
    usage=10039, value=1(Hat)
    usage=10039, value=2(Hat)
    usage=10039, value=3(Hat)
    usage=10039, value=4(Hat)
    usage=10039, value=5(Hat)
    usage=10039, value=6(Hat)
So most of the stuff looks like it is doing stuff... But wondering about the last Slider
Actually looks like there are 15 of them... So you may want to double check...
 
Last edited:
Interesting, it appears to be working for you, if you have the chance, what does joy.cpl show? I believe the last slider being 0 is due to
Code:
for (uint8_t i = 1; i < 15; i++)
where the 15 should be 16 if you wanted to use them all. As for my situation it still looks like only 4 hats are working but it's very strange, when I set the mode to flight sim + joystick joy.cpl actually shows some axis, buttons, and 4 hats View attachment 28797 however when I set the mode to Serial/Keyboard/Mouse/Joystick like you have done in your test, I get the same result as in my post above. I will try to make my own usb type that is just serial + joystick but I was wondering if anyone knows why this behavior might occur. I was also thinking that maybe there is some restriction about going above 4 hats somewhere?? Both joy.cpl and the program I am trying to get this to work for (FRC's drivers station) both show only 4 hats. I do not have another teensy currently but could get have one soon, would be nice to confirm that it is working the same way as yours.
 
Last edited:
Sorry for some reason I thought there were 14 sliders not 15...

As for how the hosts deal with a non-standard setup... Not sure. Sorry Maybe someone who uses these might have some more insight
 
Darn, I am really lost. I looked at the raw hid data as you have and got the same result with the 12 hats showing up in the last 6 bytes. rawhid.png I am having a lot trouble getting any program to recognize more than 4 however. Maybe Paul knows something more? Although if anyone else has ideas I would love to hear them. I have tried using pointys joystick tester and it only shows 4 hats. Same with joy.cpl. On Linux only 1 shows from jstest-gtk. Does anyone have ideas of what's going on? Descriptor is above along with modified hat function if someone wants to test locally.
 
Some questions I still have, Why can joy.cpl and other figure out the axis/buttons/some hats when the usb type is flightsim + joystick or even keyboard/mouse/joystick but not when it is serial/keyboard/mouse/joystick? Is there some limit of the amount of hats detected by windows/other programs?
 
Again Sorry, as I mentioned I have never used Joysticks on PC so it is unclear to me, what application code uses on the different platforms.
And/Or is it configurable.

I know some google responses to questions like this say things like:

And point you to things like: http://www.qlcplus.org/forum/viewtopic.php?t=7016
https://docs.microsoft.com/en-us/wi...pi/ns-joystickapi-joycaps?redirectedfrom=MSDN

But I don't know if you are limited or if there are other facilities to be driven directly by the HID, like we have in the example sketch
 
Alright been a while, but I think I finally know the answer. If you are making a custom application and can read the raw hid values then you can use as many hats a you want. However some applications use libraries such as GLFW (at least in my case) to parse joystick inputs. In that case, see https://github.com/glfw/glfw/blob/a465c1c32e0754d3de56e01c59a0fef33202f04c/src/win32_joystick.c#L87 which I believe limits the hat count to 4. If anyone has any success with 12 hat joysticks, I would be interested to hear about it. HID descriptor above.
 
Back
Top