فهرست منبع

joystick: Add initial support for GIP flight sticks

At the moment, only the ThrustMaster T.Flight Hotas One has full support. The
documentation says you can query the extra buttons via a specific command, but
the stick appears to reject the command. Further investigation is needed for
automatically querying this state.
Vicki Pfau 10 ماه پیش
والد
کامیت
72dd79752e
2فایلهای تغییر یافته به همراه93 افزوده شده و 0 حذف شده
  1. 92 0
      src/joystick/hidapi/SDL_hidapi_gip.c
  2. 1 0
      src/joystick/usb_ids.h

+ 92 - 0
src/joystick/hidapi/SDL_hidapi_gip.c

@@ -314,6 +314,8 @@ typedef struct GIP_Quirks
     Uint32 extra_in_system[8];
     Uint32 extra_out_system[8];
     GIP_AttachmentType device_type;
+    Uint8 extra_buttons;
+    Uint8 extra_axes;
 } GIP_Quirks;
 
 static const GIP_Quirks quirks[] = {
@@ -348,6 +350,12 @@ static const GIP_Quirks quirks[] = {
       .filtered_features = GIP_FEATURE_MOTOR_CONTROL,
       .device_type = GIP_TYPE_ARCADE_STICK },
 
+    { USB_VENDOR_THRUSTMASTER, USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE, 0,
+      .filtered_features = GIP_FEATURE_MOTOR_CONTROL,
+      .device_type = GIP_TYPE_FLIGHT_STICK,
+      .extra_buttons = 5,
+      .extra_axes = 3 },
+
     {0},
 };
 
@@ -451,6 +459,10 @@ typedef struct GIP_Attachment
     Uint8 share_button_idx;
     Uint8 paddle_idx;
     int paddle_offset;
+
+    Uint8 extra_button_idx;
+    int extra_buttons;
+    int extra_axes;
 } GIP_Attachment;
 
 typedef struct GIP_Device
@@ -658,6 +670,9 @@ static void GIP_HandleQuirks(GIP_Attachment *attachment)
             attachment->metadata.device.in_system_messages[j] |= quirks[i].extra_in_system[j];
             attachment->metadata.device.out_system_messages[j] |= quirks[i].extra_out_system[j];
         }
+
+        attachment->extra_buttons = quirks[i].extra_buttons;
+        attachment->extra_axes = quirks[i].extra_axes;
         break;
     }
 }
@@ -1168,6 +1183,10 @@ static bool GIP_SendInitSequence(GIP_Attachment *attachment)
         GIP_SendVendorMessage(attachment, GIP_CMD_INITIAL_REPORTS_REQUEST, 0, (const Uint8 *)&request, sizeof(request));
     }
 
+    if (GIP_SupportsVendorMessage(attachment, GIP_CMD_DEVICE_CAPABILITIES, false)) {
+        GIP_SendVendorMessage(attachment, GIP_CMD_DEVICE_CAPABILITIES, 0, NULL, 0);
+    }
+
     if (!attachment->joystick) {
         return HIDAPI_JoystickConnected(attachment->device->device, &attachment->joystick);
     }
@@ -1833,6 +1852,67 @@ static void GIP_HandleArcadeStickReport(
     }
 }
 
+static void GIP_HandleFlightStickReport(
+    GIP_Attachment *attachment,
+    SDL_Joystick *joystick,
+    Uint64 timestamp,
+    const Uint8 *bytes,
+    int num_bytes)
+{
+    Sint16 axis;
+    int i;
+
+    if (num_bytes < 19) {
+        return;
+    }
+
+    if (attachment->last_input[2] != bytes[2]) {
+        /* Fire 1 and 2 */
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((bytes[2] & 0x01) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((bytes[2] & 0x02) != 0));
+    }
+    for (i = 0; i < attachment->extra_buttons;) {
+        if (attachment->last_input[i / 8 + 3] != bytes[i / 8 + 3]) {
+            for (; i < attachment->extra_buttons; i++) {
+                SDL_SendJoystickButton(timestamp,
+                    joystick,
+                    (Uint8) (attachment->extra_button_idx + i),
+                    ((bytes[i / 8 + 3] & (1u << i)) != 0));
+            }
+        } else {
+            i += 8;
+        }
+    }
+
+    /* Roll, pitch and yaw are signed. Throttle and any extra axes are unsigned. All values are full-range. */
+    axis = bytes[11];
+    axis |= bytes[12] << 8;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
+
+    axis = bytes[13];
+    axis |= bytes[14] << 8;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
+
+    axis = bytes[15];
+    axis |= bytes[16] << 8;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
+
+    /* There are no more signed values, so skip RIGHTY */
+
+    axis = (bytes[18] << 8) - 0x8000;
+    axis |= bytes[17];
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
+
+    for (i = 0; i < attachment->extra_axes; i++) {
+        if (20 + i * 2 >= num_bytes) {
+            return;
+        }
+        axis = (bytes[20 + i * 2] << 8) - 0x8000;
+        axis |= bytes[19 + i * 2];
+        SDL_SendJoystickAxis(timestamp, joystick, (Uint8) (SDL_GAMEPAD_AXIS_RIGHT_TRIGGER + i), axis);
+    }
+}
+
 static bool GIP_HandleLLInputReport(
     GIP_Attachment *attachment,
     const GIP_Header *header,
@@ -1875,6 +1955,9 @@ static bool GIP_HandleLLInputReport(
     case GIP_TYPE_ARCADE_STICK:
         GIP_HandleArcadeStickReport(attachment, joystick, timestamp, bytes, num_bytes);
         break;
+    case GIP_TYPE_FLIGHT_STICK:
+        GIP_HandleFlightStickReport(attachment, joystick, timestamp, bytes, num_bytes);
+        break;
     }
 
     if ((attachment->features & GIP_FEATURE_ELITE_BUTTONS) &&
@@ -2395,8 +2478,17 @@ static bool HIDAPI_DriverGIP_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystic
         attachment->share_button_idx = (Uint8) joystick->nbuttons;
         joystick->nbuttons++;
     }
+    if (attachment->extra_buttons > 0) {
+        attachment->extra_button_idx = (Uint8) joystick->nbuttons;
+        joystick->nbuttons += attachment->extra_buttons;
+    }
 
     joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
+    if (attachment->attachment_type == GIP_TYPE_FLIGHT_STICK) {
+        /* Flight sticks have at least 4 axes, but only 3 are signed values, so we leave RIGHTY unused */
+        joystick->naxes += attachment->extra_axes - 1;
+    }
+
     joystick->nhats = 1;
 
     return true;

+ 1 - 0
src/joystick/usb_ids.h

@@ -131,6 +131,7 @@
 #define USB_PRODUCT_STEALTH_ULTRA_WIRED                   0x7073
 #define USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER            0x0575
 #define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_PS4           0xd00e
+#define USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE       0xb68c
 #define USB_PRODUCT_VALVE_STEAM_CONTROLLER_DONGLE         0x1142
 #define USB_PRODUCT_VICTRIX_FS_PRO                        0x0203
 #define USB_PRODUCT_VICTRIX_FS_PRO_V2                     0x0207