I'm doing some experiments with large numbers of buttons and axes and found an issue with the Joystick.hat() method.

Original code:

Code:
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[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;
  }
  if (!manual_mode) usb_joystick_send();
}
Note that in this case, if angle is -1 (centered), val is initially set to 15 (correct), but then through the course of the if statements is set to 1 (because -1 < 68). Also, an angle of 0 (up) will also result in val being 1, because the first if has angle > 0, not angle >= 0. In any case, this is what I changed it to and this works beautifully (it is more like the non-extreme code):

Code:
inline void hat(unsigned int num, int angle) {
  uint32_t val=15;
  if (angle < 0) val = 15;
  else if (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[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;
  }
  if (!manual_mode) usb_joystick_send();
}
One side note: It seems that Windows enumerates sliders in reverse order. The standard joystick control panel only shows 2 sliders, but they actuate on slider 17 and 16. Interestingly, this control panel doesn't change in any way if I replace the first six axes with six other sliders in the HID descriptor. It still recognizes the first 6 as the standard 6 degrees of freedom, then enumerates the remaining sliders in inverted order. This is not an issue with the Teensy software, as my controller code is calling Joystick.analog16() directly (I made it public for this) for all axes and sliders, and a test app using NodeJS finds all the values in the expected order in the packet. I don't know if it is worth changing the Joystick.slider() code to encode them in reverse order to compensate for this, or if it's just a Windows thing and not worth bothering with.

This is my first HID/Joystick project, and I'm really enjoying it. Thanks.