diff --git a/src/joystick/hidapi/SDL_hidapi_steamdeck.c b/src/joystick/hidapi/SDL_hidapi_steamdeck.c index 6adf5cb14..2ef431945 100644 --- a/src/joystick/hidapi/SDL_hidapi_steamdeck.c +++ b/src/joystick/hidapi/SDL_hidapi_steamdeck.c @@ -47,8 +47,73 @@ typedef struct Uint32 update_rate_us; Uint32 sensor_timestamp_us; Uint64 last_button_state; + Uint8 watchdog_counter; } SDL_DriverSteamDeck_Context; +static SDL_bool DisableDeckLizardMode(SDL_hid_device *dev) +{ + int rc; + Uint8 buffer[HID_FEATURE_REPORT_BYTES + 1] = { 0 }; + FeatureReportMsg *msg = (FeatureReportMsg *)(buffer + 1); + + msg->header.type = ID_CLEAR_DIGITAL_MAPPINGS; + + rc = SDL_hid_send_feature_report(dev, buffer, sizeof(buffer)); + if (rc != sizeof(buffer)) + return SDL_FALSE; + + msg->header.type = ID_SET_SETTINGS_VALUES; + msg->header.length = 5 * sizeof(WriteDeckRegister); + msg->payload.wrDeckRegister.reg[0].addr = SETTING_DECK_RPAD_MARGIN; // disable margin + msg->payload.wrDeckRegister.reg[0].val = 0; + msg->payload.wrDeckRegister.reg[1].addr = SETTING_DECK_LPAD_MODE; // disable mouse + msg->payload.wrDeckRegister.reg[1].val = 7; + msg->payload.wrDeckRegister.reg[2].addr = SETTING_DECK_RPAD_MODE; // disable mouse + msg->payload.wrDeckRegister.reg[2].val = 7; + msg->payload.wrDeckRegister.reg[3].addr = SETTING_DECK_LPAD_CLICK_PRESSURE; // disable clicky pad + msg->payload.wrDeckRegister.reg[3].val = 0xFFFF; + msg->payload.wrDeckRegister.reg[4].addr = SETTING_DECK_RPAD_CLICK_PRESSURE; // disable clicky pad + msg->payload.wrDeckRegister.reg[4].val = 0xFFFF; + + rc = SDL_hid_send_feature_report(dev, buffer, sizeof(buffer)); + if (rc != sizeof(buffer)) + return SDL_FALSE; + + // There may be a lingering report read back after changing settings. + // Discard it. + SDL_hid_get_feature_report(dev, buffer, sizeof(buffer)); + + return SDL_TRUE; +} + +static SDL_bool FeedDeckLizardWatchdog(SDL_hid_device *dev) +{ + int rc; + Uint8 buffer[HID_FEATURE_REPORT_BYTES + 1] = { 0 }; + FeatureReportMsg *msg = (FeatureReportMsg *)(buffer + 1); + + msg->header.type = ID_CLEAR_DIGITAL_MAPPINGS; + + rc = SDL_hid_send_feature_report(dev, buffer, sizeof(buffer)); + if (rc != sizeof(buffer)) + return SDL_FALSE; + + msg->header.type = ID_SET_SETTINGS_VALUES; + msg->header.length = 1 * sizeof(WriteDeckRegister); + msg->payload.wrDeckRegister.reg[0].addr = SETTING_DECK_RPAD_MODE; // disable mouse + msg->payload.wrDeckRegister.reg[0].val = 7; + + rc = SDL_hid_send_feature_report(dev, buffer, sizeof(buffer)); + if (rc != sizeof(buffer)) + return SDL_FALSE; + + // There may be a lingering report read back after changing settings. + // Discard it. + SDL_hid_get_feature_report(dev, buffer, sizeof(buffer)); + + return SDL_TRUE; +} + /*****************************************************************************************************/ static void HIDAPI_DriverSteamDeck_RegisterHints(SDL_HintCallback callback, void *userdata) @@ -106,6 +171,9 @@ static SDL_bool HIDAPI_DriverSteamDeck_InitDevice(SDL_HIDAPI_Device *device) if (size == 0) return SDL_FALSE; + if (!DisableDeckLizardMode(device->dev)) + return SDL_FALSE; + HIDAPI_SetDeviceName(device, "Steam Deck"); return HIDAPI_JoystickConnected(device, NULL); @@ -138,6 +206,12 @@ static SDL_bool HIDAPI_DriverSteamDeck_UpdateDevice(SDL_HIDAPI_Device *device) return SDL_FALSE; } + if (ctx->watchdog_counter++ > 200) { + ctx->watchdog_counter = 0; + if (!FeedDeckLizardWatchdog(device->dev)) + return SDL_FALSE; + } + SDL_memset(data, 0, sizeof(data)); r = SDL_hid_read(device->dev, data, sizeof(data)); if (r == 0) { diff --git a/src/joystick/hidapi/steam/controller_constants.h b/src/joystick/hidapi/steam/controller_constants.h index 42c84f247..dc0c3f220 100644 --- a/src/joystick/hidapi/steam/controller_constants.h +++ b/src/joystick/hidapi/steam/controller_constants.h @@ -467,6 +467,15 @@ typedef enum SETTING_ALL=0xFF } ControllerSettings; +typedef enum +{ + SETTING_DECK_LPAD_MODE = 0x07, + SETTING_DECK_RPAD_MODE = 0x08, + SETTING_DECK_RPAD_MARGIN = 0x18, + SETTING_DECK_LPAD_CLICK_PRESSURE = 0x34, + SETTING_DECK_RPAD_CLICK_PRESSURE = 0x35 +} DeckSettings; + typedef enum { SETTING_DEFAULT, diff --git a/src/joystick/hidapi/steam/controller_structs.h b/src/joystick/hidapi/steam/controller_structs.h index fd9f46e7b..205e4d669 100644 --- a/src/joystick/hidapi/steam/controller_structs.h +++ b/src/joystick/hidapi/steam/controller_structs.h @@ -45,6 +45,19 @@ typedef struct ControllerAttribute attributes[ ( HID_FEATURE_REPORT_BYTES - sizeof( FeatureReportHeader ) ) / sizeof( ControllerAttribute ) ]; } MsgGetAttributes; +// 16bit Steam Deck register with address +typedef struct +{ + uint8_t addr; + uint16_t val; +} WriteDeckRegister; + +// Generic Steam Deck write register message +typedef struct +{ + WriteDeckRegister reg[ (HID_FEATURE_REPORT_BYTES - sizeof ( FeatureReportHeader ) ) / sizeof (WriteDeckRegister ) ]; +} MsgWriteDeckRegister; + // This is the only message struct that application code should use to interact with feature request messages. Any new // messages should be added to the union. The structures defined here should correspond to the ones defined in @@ -56,6 +69,7 @@ typedef struct union { MsgGetAttributes getAttributes; + MsgWriteDeckRegister wrDeckRegister; } payload; } FeatureReportMsg;