Path: blob/master/thirdparty/sdl/joystick/hidapi/SDL_hidapi_shield.c
9906 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122#ifdef SDL_JOYSTICK_HIDAPI2324#include "../SDL_sysjoystick.h"25#include "SDL_hidapijoystick_c.h"26#include "SDL_hidapi_rumble.h"2728#ifdef SDL_JOYSTICK_HIDAPI_SHIELD2930// Define this if you want to log all packets from the controller31// #define DEBUG_SHIELD_PROTOCOL3233#define CMD_BATTERY_STATE 0x0734#define CMD_RUMBLE 0x3935#define CMD_CHARGE_STATE 0x3A3637// Milliseconds between polls of battery state38#define BATTERY_POLL_INTERVAL_MS 600003940// Milliseconds between retransmission of rumble to keep motors running41#define RUMBLE_REFRESH_INTERVAL_MS 5004243// Reports that are too small are dropped over Bluetooth44#define HID_REPORT_SIZE 334546enum47{48SDL_GAMEPAD_BUTTON_SHIELD_SHARE = 11,49SDL_GAMEPAD_BUTTON_SHIELD_V103_TOUCHPAD,50SDL_GAMEPAD_BUTTON_SHIELD_V103_MINUS,51SDL_GAMEPAD_BUTTON_SHIELD_V103_PLUS,52SDL_GAMEPAD_NUM_SHIELD_V103_BUTTONS,5354SDL_GAMEPAD_NUM_SHIELD_V104_BUTTONS = SDL_GAMEPAD_BUTTON_SHIELD_SHARE + 1,55};5657typedef enum58{59k_ShieldReportIdControllerState = 0x01,60k_ShieldReportIdControllerTouch = 0x02,61k_ShieldReportIdCommandResponse = 0x03,62k_ShieldReportIdCommandRequest = 0x04,63} EShieldReportId;6465// This same report structure is used for both requests and responses66typedef struct67{68Uint8 report_id;69Uint8 cmd;70Uint8 seq_num;71Uint8 payload[HID_REPORT_SIZE - 3];72} ShieldCommandReport_t;73SDL_COMPILE_TIME_ASSERT(ShieldCommandReport_t, sizeof(ShieldCommandReport_t) == HID_REPORT_SIZE);7475typedef struct76{77Uint8 seq_num;7879bool has_charging;80Uint8 charging;81bool has_battery_level;82Uint8 battery_level;83Uint64 last_battery_query_time;8485bool rumble_report_pending;86bool rumble_update_pending;87Uint8 left_motor_amplitude;88Uint8 right_motor_amplitude;89Uint64 last_rumble_time;9091Uint8 last_state[USB_PACKET_LENGTH];92} SDL_DriverShield_Context;9394static void HIDAPI_DriverShield_RegisterHints(SDL_HintCallback callback, void *userdata)95{96SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);97}9899static void HIDAPI_DriverShield_UnregisterHints(SDL_HintCallback callback, void *userdata)100{101SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);102}103104static bool HIDAPI_DriverShield_IsEnabled(void)105{106return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));107}108109static bool HIDAPI_DriverShield_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)110{111return SDL_IsJoystickNVIDIASHIELDController(vendor_id, product_id);112}113114static bool HIDAPI_DriverShield_InitDevice(SDL_HIDAPI_Device *device)115{116SDL_DriverShield_Context *ctx;117118ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx));119if (!ctx) {120return false;121}122device->context = ctx;123124HIDAPI_SetDeviceName(device, "NVIDIA SHIELD Controller");125126return HIDAPI_JoystickConnected(device, NULL);127}128129static int HIDAPI_DriverShield_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)130{131return -1;132}133134static void HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)135{136}137138static bool HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size)139{140SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;141ShieldCommandReport_t cmd_pkt;142143if (size > sizeof(cmd_pkt.payload)) {144return SDL_SetError("Command data exceeds HID report size");145}146147if (!SDL_HIDAPI_LockRumble()) {148return false;149}150151cmd_pkt.report_id = k_ShieldReportIdCommandRequest;152cmd_pkt.cmd = cmd;153cmd_pkt.seq_num = ctx->seq_num++;154if (data) {155SDL_memcpy(cmd_pkt.payload, data, size);156}157158// Zero unused data in the payload159if (size != sizeof(cmd_pkt.payload)) {160SDL_memset(&cmd_pkt.payload[size], 0, sizeof(cmd_pkt.payload) - size);161}162163if (SDL_HIDAPI_SendRumbleAndUnlock(device, (Uint8 *)&cmd_pkt, sizeof(cmd_pkt)) != sizeof(cmd_pkt)) {164return SDL_SetError("Couldn't send command packet");165}166167return true;168}169170static bool HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)171{172SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;173174SDL_AssertJoysticksLocked();175176ctx->rumble_report_pending = false;177ctx->rumble_update_pending = false;178ctx->left_motor_amplitude = 0;179ctx->right_motor_amplitude = 0;180ctx->last_rumble_time = 0;181SDL_zeroa(ctx->last_state);182183// Initialize the joystick capabilities184if (device->product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {185joystick->nbuttons = SDL_GAMEPAD_NUM_SHIELD_V103_BUTTONS;186joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;187joystick->nhats = 1;188189SDL_PrivateJoystickAddTouchpad(joystick, 1);190} else {191joystick->nbuttons = SDL_GAMEPAD_NUM_SHIELD_V104_BUTTONS;192joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;193joystick->nhats = 1;194}195196// Request battery and charging info197ctx->last_battery_query_time = SDL_GetTicks();198HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0);199HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);200201return true;202}203204static bool HIDAPI_DriverShield_SendNextRumble(SDL_HIDAPI_Device *device)205{206SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;207Uint8 rumble_data[3];208209if (!ctx->rumble_update_pending) {210return true;211}212213rumble_data[0] = 0x01; // enable214rumble_data[1] = ctx->left_motor_amplitude;215rumble_data[2] = ctx->right_motor_amplitude;216217ctx->rumble_update_pending = false;218ctx->last_rumble_time = SDL_GetTicks();219220return HIDAPI_DriverShield_SendCommand(device, CMD_RUMBLE, rumble_data, sizeof(rumble_data));221}222223static bool HIDAPI_DriverShield_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)224{225if (device->product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {226Uint8 rumble_packet[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };227228rumble_packet[2] = (low_frequency_rumble >> 8);229rumble_packet[4] = (high_frequency_rumble >> 8);230231if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {232return SDL_SetError("Couldn't send rumble packet");233}234return true;235236} else {237SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;238239// The rumble motors are quite intense, so tone down the intensity like the official driver does240ctx->left_motor_amplitude = low_frequency_rumble >> 11;241ctx->right_motor_amplitude = high_frequency_rumble >> 11;242ctx->rumble_update_pending = true;243244if (ctx->rumble_report_pending) {245// We will service this after the hardware acknowledges the previous request246return true;247}248249return HIDAPI_DriverShield_SendNextRumble(device);250}251}252253static bool HIDAPI_DriverShield_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)254{255return SDL_Unsupported();256}257258static Uint32 HIDAPI_DriverShield_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)259{260return SDL_JOYSTICK_CAP_RUMBLE;261}262263static bool HIDAPI_DriverShield_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)264{265return SDL_Unsupported();266}267268static bool HIDAPI_DriverShield_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)269{270const Uint8 *data_bytes = (const Uint8 *)data;271272if (size > 1) {273// Single command byte followed by a variable length payload274return HIDAPI_DriverShield_SendCommand(device, data_bytes[0], &data_bytes[1], size - 1);275} else if (size == 1) {276// Single command byte with no payload277return HIDAPI_DriverShield_SendCommand(device, data_bytes[0], NULL, 0);278} else {279return SDL_SetError("Effect data must at least contain a command byte");280}281}282283static bool HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)284{285return SDL_Unsupported();286}287288static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)289{290Uint64 timestamp = SDL_GetTicksNS();291292if (ctx->last_state[3] != data[3]) {293Uint8 hat;294295switch (data[3]) {296case 0:297hat = SDL_HAT_UP;298break;299case 1:300hat = SDL_HAT_RIGHTUP;301break;302case 2:303hat = SDL_HAT_RIGHT;304break;305case 3:306hat = SDL_HAT_RIGHTDOWN;307break;308case 4:309hat = SDL_HAT_DOWN;310break;311case 5:312hat = SDL_HAT_LEFTDOWN;313break;314case 6:315hat = SDL_HAT_LEFT;316break;317case 7:318hat = SDL_HAT_LEFTUP;319break;320default:321hat = SDL_HAT_CENTERED;322break;323}324SDL_SendJoystickHat(timestamp, joystick, 0, hat);325}326327if (ctx->last_state[1] != data[1]) {328SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[1] & 0x01) != 0));329SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[1] & 0x02) != 0));330SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[1] & 0x04) != 0));331SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[1] & 0x08) != 0));332SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[1] & 0x10) != 0));333SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[1] & 0x20) != 0));334SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x40) != 0));335SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x80) != 0));336}337338if (ctx->last_state[2] != data[2]) {339SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[2] & 0x02) != 0));340SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_V103_PLUS, ((data[2] & 0x08) != 0));341SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_V103_MINUS, ((data[2] & 0x10) != 0));342//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[2] & 0x20) != 0));343SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[2] & 0x40) != 0));344//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_SHARE, ((data[2] & 0x80) != 0));345SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[2] & 0x80) != 0));346}347348SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[4]) - 0x8000);349SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[6]) - 0x8000);350351SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[8]) - 0x8000);352SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[10]) - 0x8000);353354SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[12]) - 0x8000);355SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[14]) - 0x8000);356357SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));358}359360#undef clamp361#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))362363static void HIDAPI_DriverShield_HandleTouchPacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, const Uint8 *data, int size)364{365bool touchpad_down;366float touchpad_x, touchpad_y;367Uint64 timestamp = SDL_GetTicksNS();368369SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_V103_TOUCHPAD, ((data[1] & 0x01) != 0));370371// It's a triangular pad, but just use the center as the usable touch area372touchpad_down = ((data[1] & 0x80) == 0);373touchpad_x = clamp((float)(data[2] - 0x70) / 0x50, 0.0f, 1.0f);374touchpad_y = clamp((float)(data[4] - 0x40) / 0x15, 0.0f, 1.0f);375SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, touchpad_down, touchpad_x, touchpad_y, touchpad_down ? 1.0f : 0.0f);376}377378static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)379{380Uint64 timestamp = SDL_GetTicksNS();381382if (size < 23) {383return;384}385386if (ctx->last_state[2] != data[2]) {387Uint8 hat;388389switch (data[2]) {390case 0:391hat = SDL_HAT_UP;392break;393case 1:394hat = SDL_HAT_RIGHTUP;395break;396case 2:397hat = SDL_HAT_RIGHT;398break;399case 3:400hat = SDL_HAT_RIGHTDOWN;401break;402case 4:403hat = SDL_HAT_DOWN;404break;405case 5:406hat = SDL_HAT_LEFTDOWN;407break;408case 6:409hat = SDL_HAT_LEFT;410break;411case 7:412hat = SDL_HAT_LEFTUP;413break;414default:415hat = SDL_HAT_CENTERED;416break;417}418SDL_SendJoystickHat(timestamp, joystick, 0, hat);419}420421if (ctx->last_state[3] != data[3]) {422SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x01) != 0));423SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x02) != 0));424SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x04) != 0));425SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x08) != 0));426SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[3] & 0x10) != 0));427SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x20) != 0));428SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[3] & 0x40) != 0));429SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[3] & 0x80) != 0));430}431432if (ctx->last_state[4] != data[4]) {433SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[4] & 0x01) != 0));434}435436SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[9]) - 0x8000);437SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[11]) - 0x8000);438439SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[13]) - 0x8000);440SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[15]) - 0x8000);441442SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[19]) - 0x8000);443SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[21]) - 0x8000);444445if (ctx->last_state[17] != data[17]) {446//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_SHARE, ((data[17] & 0x01) != 0));447SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[17] & 0x02) != 0));448//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[17] & 0x04) != 0));449SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[17] & 0x01) != 0));450}451452SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));453}454455static void HIDAPI_DriverShield_UpdatePowerInfo(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx)456{457if (!ctx->has_charging || !ctx->has_battery_level) {458return;459}460461SDL_PowerState state = ctx->charging ? SDL_POWERSTATE_CHARGING : SDL_POWERSTATE_ON_BATTERY;462int percent = ctx->battery_level * 20;463SDL_SendJoystickPowerInfo(joystick, state, percent);464}465466static bool HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)467{468SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;469SDL_Joystick *joystick = NULL;470Uint8 data[USB_PACKET_LENGTH];471int size = 0;472ShieldCommandReport_t *cmd_resp_report;473474if (device->num_joysticks > 0) {475joystick = SDL_GetJoystickFromID(device->joysticks[0]);476} else {477return false;478}479480while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {481#ifdef DEBUG_SHIELD_PROTOCOL482HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);483#endif484485// Byte 0 is HID report ID486switch (data[0]) {487case k_ShieldReportIdControllerState:488if (!joystick) {489break;490}491if (size == 16) {492HIDAPI_DriverShield_HandleStatePacketV103(joystick, ctx, data, size);493} else {494HIDAPI_DriverShield_HandleStatePacketV104(joystick, ctx, data, size);495}496break;497case k_ShieldReportIdControllerTouch:498if (!joystick) {499break;500}501HIDAPI_DriverShield_HandleTouchPacketV103(joystick, ctx, data, size);502break;503case k_ShieldReportIdCommandResponse:504cmd_resp_report = (ShieldCommandReport_t *)data;505switch (cmd_resp_report->cmd) {506case CMD_RUMBLE:507ctx->rumble_report_pending = false;508HIDAPI_DriverShield_SendNextRumble(device);509break;510case CMD_CHARGE_STATE:511ctx->has_charging = true;512ctx->charging = cmd_resp_report->payload[0];513HIDAPI_DriverShield_UpdatePowerInfo(joystick, ctx);514break;515case CMD_BATTERY_STATE:516ctx->has_battery_level = true;517ctx->battery_level = cmd_resp_report->payload[2];518HIDAPI_DriverShield_UpdatePowerInfo(joystick, ctx);519break;520}521break;522}523}524525// Ask for battery state again if we're due for an update526if (joystick && SDL_GetTicks() >= (ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) {527ctx->last_battery_query_time = SDL_GetTicks();528HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);529}530531// Retransmit rumble packets if they've lasted longer than the hardware supports532if ((ctx->left_motor_amplitude != 0 || ctx->right_motor_amplitude != 0) &&533SDL_GetTicks() >= (ctx->last_rumble_time + RUMBLE_REFRESH_INTERVAL_MS)) {534ctx->rumble_update_pending = true;535HIDAPI_DriverShield_SendNextRumble(device);536}537538if (size < 0) {539// Read error, device is disconnected540HIDAPI_JoystickDisconnected(device, device->joysticks[0]);541}542return (size >= 0);543}544545static void HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)546{547}548549static void HIDAPI_DriverShield_FreeDevice(SDL_HIDAPI_Device *device)550{551}552553SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield = {554SDL_HINT_JOYSTICK_HIDAPI_SHIELD,555true,556HIDAPI_DriverShield_RegisterHints,557HIDAPI_DriverShield_UnregisterHints,558HIDAPI_DriverShield_IsEnabled,559HIDAPI_DriverShield_IsSupportedDevice,560HIDAPI_DriverShield_InitDevice,561HIDAPI_DriverShield_GetDevicePlayerIndex,562HIDAPI_DriverShield_SetDevicePlayerIndex,563HIDAPI_DriverShield_UpdateDevice,564HIDAPI_DriverShield_OpenJoystick,565HIDAPI_DriverShield_RumbleJoystick,566HIDAPI_DriverShield_RumbleJoystickTriggers,567HIDAPI_DriverShield_GetJoystickCapabilities,568HIDAPI_DriverShield_SetJoystickLED,569HIDAPI_DriverShield_SendJoystickEffect,570HIDAPI_DriverShield_SetJoystickSensorsEnabled,571HIDAPI_DriverShield_CloseJoystick,572HIDAPI_DriverShield_FreeDevice,573};574575#endif // SDL_JOYSTICK_HIDAPI_SHIELD576577#endif // SDL_JOYSTICK_HIDAPI578579580