Translate steam deck HID reports to SDL events.

main
Max Maisel 2023-09-07 17:18:12 +02:00 committed by Sam Lantinga
parent 94f621e030
commit 6dd6827343
3 changed files with 213 additions and 1 deletions

View File

@ -31,9 +31,21 @@
#include <stdint.h> #include <stdint.h>
#define bool SDL_bool
#define true SDL_TRUE
#define false SDL_FALSE
typedef uint32_t uint32;
typedef uint64_t uint64;
#include "steam/controller_constants.h"
#include "steam/controller_structs.h"
typedef struct typedef struct
{ {
Uint32 update_rate_us; Uint32 update_rate_us;
Uint32 sensor_timestamp_us;
Uint64 last_button_state;
} SDL_DriverSteamDeck_Context; } SDL_DriverSteamDeck_Context;
/*****************************************************************************************************/ /*****************************************************************************************************/
@ -109,8 +121,115 @@ static void HIDAPI_DriverSteamDeck_SetDevicePlayerIndex(SDL_HIDAPI_Device *devic
static SDL_bool HIDAPI_DriverSteamDeck_UpdateDevice(SDL_HIDAPI_Device *device) static SDL_bool HIDAPI_DriverSteamDeck_UpdateDevice(SDL_HIDAPI_Device *device)
{ {
SDL_DriverSteamDeck_Context *ctx = (SDL_DriverSteamDeck_Context *)device->context;
SDL_Joystick *joystick = NULL;
int r;
uint8_t data[64];
float values[3];
ValveInReport_t *pInReport = (ValveInReport_t *)data;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
if (joystick == NULL) {
return SDL_FALSE; return SDL_FALSE;
} }
} else {
return SDL_FALSE;
}
SDL_memset(data, 0, sizeof(data));
r = SDL_hid_read(device->dev, data, sizeof(data));
if (r == 0) {
return SDL_FALSE;
} else if (r <= 0) {
/* Failed to read from controller */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
return SDL_FALSE;
}
if (!(r == 64 && pInReport->header.unReportVersion == k_ValveInReportMsgVersion && pInReport->header.ucType == ID_CONTROLLER_DECK_STATE && pInReport->header.ucLength == 64)) {
return SDL_FALSE;
}
Uint64 timestamp = SDL_GetTicksNS();
if (pInReport->payload.deckState.ulButtons != ctx->last_button_state) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_A) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_B) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_X) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_Y) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_LT) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_RT) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_SELECT) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_START) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_MODE) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC1,
(pInReport->payload.deckState.ulButtonsH & STEAMDECK_HBUTTON_BASE) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_STICKL) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_STICKR) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1,
(pInReport->payload.deckState.ulButtonsH & STEAMDECK_HBUTTON_PADDLE1) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_PADDLE1,
(pInReport->payload.deckState.ulButtonsH & STEAMDECK_HBUTTON_PADDLE2) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_PADDLE3) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_PADDLE2,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_PADDLE4) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_DPAD_UP) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_DPAD_DOWN) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_DPAD_LEFT) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT,
(pInReport->payload.deckState.ulButtonsL & STEAMDECK_LBUTTON_DPAD_RIGHT) ? SDL_PRESSED : SDL_RELEASED);
ctx->last_button_state = pInReport->payload.deckState.ulButtons;
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER,
(int)pInReport->payload.deckState.sLeftTrigger * 2 - 32768);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER,
(int)pInReport->payload.deckState.sRightTrigger * 2 - 32768);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX,
pInReport->payload.deckState.sLeftStickX);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY,
-pInReport->payload.deckState.sLeftStickY);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX,
pInReport->payload.deckState.sRightStickX);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY,
-pInReport->payload.deckState.sRightStickY);
ctx->sensor_timestamp_us += ctx->update_rate_us;
values[0] = (pInReport->payload.deckState.sGyroX / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
values[1] = (pInReport->payload.deckState.sGyroZ / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
values[2] = (-pInReport->payload.deckState.sGyroY / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, ctx->sensor_timestamp_us, values, 3);
values[0] = (pInReport->payload.deckState.sAccelX / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
values[1] = (pInReport->payload.deckState.sAccelZ / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
values[2] = (-pInReport->payload.deckState.sAccelY / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, ctx->sensor_timestamp_us, values, 3);
return SDL_TRUE;
}
static SDL_bool HIDAPI_DriverSteamDeck_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) static SDL_bool HIDAPI_DriverSteamDeck_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{ {

View File

@ -315,6 +315,37 @@ enum GamepadButtons
GAMEPAD_BTN_COUNT GAMEPAD_BTN_COUNT
}; };
typedef enum
{
// Low word button bits
STEAMDECK_LBUTTON_RT2 = (1 << 0),
STEAMDECK_LBUTTON_LT2 = (1 << 1),
STEAMDECK_LBUTTON_RT = (1 << 2),
STEAMDECK_LBUTTON_LT = (1 << 3),
STEAMDECK_LBUTTON_Y = (1 << 4),
STEAMDECK_LBUTTON_B = (1 << 5),
STEAMDECK_LBUTTON_X = (1 << 6),
STEAMDECK_LBUTTON_A = (1 << 7),
STEAMDECK_LBUTTON_DPAD_UP = (1 << 8),
STEAMDECK_LBUTTON_DPAD_RIGHT = (1 << 9),
STEAMDECK_LBUTTON_DPAD_LEFT = (1 << 10),
STEAMDECK_LBUTTON_DPAD_DOWN = (1 << 11),
STEAMDECK_LBUTTON_SELECT = (1 << 12),
STEAMDECK_LBUTTON_MODE = (1 << 13),
STEAMDECK_LBUTTON_START = (1 << 14),
STEAMDECK_LBUTTON_PADDLE3 = (1 << 15),
STEAMDECK_LBUTTON_PADDLE4 = (1 << 16),
STEAMDECK_LBUTTON_PADL = (1 << 17),
STEAMDECK_LBUTTON_PADR = (1 << 18),
STEAMDECK_LBUTTON_STICKL = (1 << 22),
STEAMDECK_LBUTTON_STICKR = (1 << 26),
// High word button bits
STEAMDECK_HBUTTON_PADDLE1 = (1 << 9),
STEAMDECK_HBUTTON_PADDLE2 = (1 << 10),
STEAMDECK_HBUTTON_BASE = (1 << 18)
} DeckButtons;
// Mode adjust // Mode adjust
enum ModeAdjustModes enum ModeAdjustModes
{ {

View File

@ -77,6 +77,7 @@ typedef enum
ID_CONTROLLER_DEBUG2 = 5, ID_CONTROLLER_DEBUG2 = 5,
ID_CONTROLLER_SECONDARY_STATE = 6, ID_CONTROLLER_SECONDARY_STATE = 6,
ID_CONTROLLER_BLE_STATE = 7, ID_CONTROLLER_BLE_STATE = 7,
ID_CONTROLLER_DECK_STATE = 9,
ID_CONTROLLER_MSG_COUNT ID_CONTROLLER_MSG_COUNT
} ValveInReportMessageIDs; } ValveInReportMessageIDs;
@ -258,6 +259,66 @@ typedef struct
unsigned char ucBatteryLevel; unsigned char ucBatteryLevel;
} SteamControllerStatusEvent_t; } SteamControllerStatusEvent_t;
// Deck State payload
typedef struct
{
// If packet num matches that on your prior call, then the controller
// state hasn't been changed since your last call and there is no need to
// process it
uint32 unPacketNum;
// Button bitmask and trigger data.
union
{
uint64 ulButtons;
struct
{
uint32 ulButtonsL;
uint32 ulButtonsH;
};
};
// Left pad coordinates
short sLeftPadX;
short sLeftPadY;
// Right pad coordinates
short sRightPadX;
short sRightPadY;
// Accelerometer values
short sAccelX;
short sAccelY;
short sAccelZ;
// Gyroscope values
short sGyroX;
short sGyroY;
short sGyroZ;
// Gyro quaternions
short sGyroQuatW;
short sGyroQuatX;
short sGyroQuatY;
short sGyroQuatZ;
// Uncalibrated trigger values
short sLeftTrigger;
short sRightTrigger;
// Left stick values
short sLeftStickX;
short sLeftStickY;
// Right stick values
short sRightStickX;
short sRightStickY;
// Touchpad pressures
short sLeftPadPressure;
short sRightPadPressure;
} SteamDeckStatePacket_t;
typedef struct typedef struct
{ {
ValveInReportHeader_t header; ValveInReportHeader_t header;
@ -271,6 +332,7 @@ typedef struct
ValveControllerRawTrackpadImage_t rawPadImage; ValveControllerRawTrackpadImage_t rawPadImage;
SteamControllerWirelessEvent_t wirelessEvent; SteamControllerWirelessEvent_t wirelessEvent;
SteamControllerStatusEvent_t statusEvent; SteamControllerStatusEvent_t statusEvent;
SteamDeckStatePacket_t deckState;
} payload; } payload;
} ValveInReport_t; } ValveInReport_t;