Skip to content

Commit 72dd797

Browse files
endriftslouken
authored andcommitted
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.
1 parent 2248d38 commit 72dd797

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/joystick/hidapi/SDL_hidapi_gip.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ typedef struct GIP_Quirks
314314
Uint32 extra_in_system[8];
315315
Uint32 extra_out_system[8];
316316
GIP_AttachmentType device_type;
317+
Uint8 extra_buttons;
318+
Uint8 extra_axes;
317319
} GIP_Quirks;
318320

319321
static const GIP_Quirks quirks[] = {
@@ -348,6 +350,12 @@ static const GIP_Quirks quirks[] = {
348350
.filtered_features = GIP_FEATURE_MOTOR_CONTROL,
349351
.device_type = GIP_TYPE_ARCADE_STICK },
350352

353+
{ USB_VENDOR_THRUSTMASTER, USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE, 0,
354+
.filtered_features = GIP_FEATURE_MOTOR_CONTROL,
355+
.device_type = GIP_TYPE_FLIGHT_STICK,
356+
.extra_buttons = 5,
357+
.extra_axes = 3 },
358+
351359
{0},
352360
};
353361

@@ -451,6 +459,10 @@ typedef struct GIP_Attachment
451459
Uint8 share_button_idx;
452460
Uint8 paddle_idx;
453461
int paddle_offset;
462+
463+
Uint8 extra_button_idx;
464+
int extra_buttons;
465+
int extra_axes;
454466
} GIP_Attachment;
455467

456468
typedef struct GIP_Device
@@ -658,6 +670,9 @@ static void GIP_HandleQuirks(GIP_Attachment *attachment)
658670
attachment->metadata.device.in_system_messages[j] |= quirks[i].extra_in_system[j];
659671
attachment->metadata.device.out_system_messages[j] |= quirks[i].extra_out_system[j];
660672
}
673+
674+
attachment->extra_buttons = quirks[i].extra_buttons;
675+
attachment->extra_axes = quirks[i].extra_axes;
661676
break;
662677
}
663678
}
@@ -1168,6 +1183,10 @@ static bool GIP_SendInitSequence(GIP_Attachment *attachment)
11681183
GIP_SendVendorMessage(attachment, GIP_CMD_INITIAL_REPORTS_REQUEST, 0, (const Uint8 *)&request, sizeof(request));
11691184
}
11701185

1186+
if (GIP_SupportsVendorMessage(attachment, GIP_CMD_DEVICE_CAPABILITIES, false)) {
1187+
GIP_SendVendorMessage(attachment, GIP_CMD_DEVICE_CAPABILITIES, 0, NULL, 0);
1188+
}
1189+
11711190
if (!attachment->joystick) {
11721191
return HIDAPI_JoystickConnected(attachment->device->device, &attachment->joystick);
11731192
}
@@ -1833,6 +1852,67 @@ static void GIP_HandleArcadeStickReport(
18331852
}
18341853
}
18351854

1855+
static void GIP_HandleFlightStickReport(
1856+
GIP_Attachment *attachment,
1857+
SDL_Joystick *joystick,
1858+
Uint64 timestamp,
1859+
const Uint8 *bytes,
1860+
int num_bytes)
1861+
{
1862+
Sint16 axis;
1863+
int i;
1864+
1865+
if (num_bytes < 19) {
1866+
return;
1867+
}
1868+
1869+
if (attachment->last_input[2] != bytes[2]) {
1870+
/* Fire 1 and 2 */
1871+
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((bytes[2] & 0x01) != 0));
1872+
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((bytes[2] & 0x02) != 0));
1873+
}
1874+
for (i = 0; i < attachment->extra_buttons;) {
1875+
if (attachment->last_input[i / 8 + 3] != bytes[i / 8 + 3]) {
1876+
for (; i < attachment->extra_buttons; i++) {
1877+
SDL_SendJoystickButton(timestamp,
1878+
joystick,
1879+
(Uint8) (attachment->extra_button_idx + i),
1880+
((bytes[i / 8 + 3] & (1u << i)) != 0));
1881+
}
1882+
} else {
1883+
i += 8;
1884+
}
1885+
}
1886+
1887+
/* Roll, pitch and yaw are signed. Throttle and any extra axes are unsigned. All values are full-range. */
1888+
axis = bytes[11];
1889+
axis |= bytes[12] << 8;
1890+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
1891+
1892+
axis = bytes[13];
1893+
axis |= bytes[14] << 8;
1894+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
1895+
1896+
axis = bytes[15];
1897+
axis |= bytes[16] << 8;
1898+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
1899+
1900+
/* There are no more signed values, so skip RIGHTY */
1901+
1902+
axis = (bytes[18] << 8) - 0x8000;
1903+
axis |= bytes[17];
1904+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
1905+
1906+
for (i = 0; i < attachment->extra_axes; i++) {
1907+
if (20 + i * 2 >= num_bytes) {
1908+
return;
1909+
}
1910+
axis = (bytes[20 + i * 2] << 8) - 0x8000;
1911+
axis |= bytes[19 + i * 2];
1912+
SDL_SendJoystickAxis(timestamp, joystick, (Uint8) (SDL_GAMEPAD_AXIS_RIGHT_TRIGGER + i), axis);
1913+
}
1914+
}
1915+
18361916
static bool GIP_HandleLLInputReport(
18371917
GIP_Attachment *attachment,
18381918
const GIP_Header *header,
@@ -1875,6 +1955,9 @@ static bool GIP_HandleLLInputReport(
18751955
case GIP_TYPE_ARCADE_STICK:
18761956
GIP_HandleArcadeStickReport(attachment, joystick, timestamp, bytes, num_bytes);
18771957
break;
1958+
case GIP_TYPE_FLIGHT_STICK:
1959+
GIP_HandleFlightStickReport(attachment, joystick, timestamp, bytes, num_bytes);
1960+
break;
18781961
}
18791962

18801963
if ((attachment->features & GIP_FEATURE_ELITE_BUTTONS) &&
@@ -2395,8 +2478,17 @@ static bool HIDAPI_DriverGIP_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystic
23952478
attachment->share_button_idx = (Uint8) joystick->nbuttons;
23962479
joystick->nbuttons++;
23972480
}
2481+
if (attachment->extra_buttons > 0) {
2482+
attachment->extra_button_idx = (Uint8) joystick->nbuttons;
2483+
joystick->nbuttons += attachment->extra_buttons;
2484+
}
23982485

23992486
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
2487+
if (attachment->attachment_type == GIP_TYPE_FLIGHT_STICK) {
2488+
/* Flight sticks have at least 4 axes, but only 3 are signed values, so we leave RIGHTY unused */
2489+
joystick->naxes += attachment->extra_axes - 1;
2490+
}
2491+
24002492
joystick->nhats = 1;
24012493

24022494
return true;

src/joystick/usb_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
#define USB_PRODUCT_STEALTH_ULTRA_WIRED 0x7073
132132
#define USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER 0x0575
133133
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_PS4 0xd00e
134+
#define USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE 0xb68c
134135
#define USB_PRODUCT_VALVE_STEAM_CONTROLLER_DONGLE 0x1142
135136
#define USB_PRODUCT_VICTRIX_FS_PRO 0x0203
136137
#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207

0 commit comments

Comments
 (0)