diff --git a/app/streaming/input/gamepad.cpp b/app/streaming/input/gamepad.cpp index 79b4954a..aa0c9d52 100644 --- a/app/streaming/input/gamepad.cpp +++ b/app/streaming/input/gamepad.cpp @@ -312,6 +312,58 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve } } +#if SDL_VERSION_ATLEAST(2, 0, 14) + +void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* event) +{ + GamepadState* state = findStateForGamepad(event->which); + if (state == NULL) { + return; + } + + switch (event->sensor) { + case SDL_SENSOR_ACCEL: + if (state->accelReportPeriodMs && SDL_TICKS_PASSED(event->timestamp, state->lastAccelEventTime + state->accelReportPeriodMs)) { + LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_ACCEL, event->data[0], event->data[1], event->data[2]); + state->lastAccelEventTime = event->timestamp; + } + break; + case SDL_SENSOR_GYRO: + if (state->gyroReportPeriodMs && SDL_TICKS_PASSED(event->timestamp, state->lastGyroEventTime + state->gyroReportPeriodMs)) { + LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_GYRO, event->data[0], event->data[1], event->data[2]); + state->lastGyroEventTime = event->timestamp; + } + break; + } +} + +void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent* event) +{ + GamepadState* state = findStateForGamepad(event->which); + if (state == NULL) { + return; + } + + uint8_t eventType; + switch (event->type) { + case SDL_CONTROLLERTOUCHPADDOWN: + eventType = LI_TOUCH_EVENT_DOWN; + break; + case SDL_CONTROLLERTOUCHPADUP: + eventType = LI_TOUCH_EVENT_UP; + break; + case SDL_CONTROLLERTOUCHPADMOTION: + eventType = LI_TOUCH_EVENT_MOVE; + break; + default: + return; + } + + LiSendControllerTouchEvent((uint8_t)state->index, eventType, event->finger, event->x, event->y, event->pressure); +} + +#endif + void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* event) { GamepadState* state; @@ -580,6 +632,32 @@ void SdlInputHandler::rumbleTriggers(uint16_t controllerNumber, uint16_t leftTri #endif } +void SdlInputHandler::setMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) +{ + // Make sure the controller number is within our supported count + if (controllerNumber >= MAX_GAMEPADS) { + return; + } + +#if SDL_VERSION_ATLEAST(2, 0, 14) + if (m_GamepadState[controllerNumber].controller != nullptr) { + uint8_t reportPeriodMs = reportRateHz ? (1000 / reportRateHz) : 0; + + switch (motionType) { + case LI_MOTION_TYPE_ACCEL: + m_GamepadState[controllerNumber].accelReportPeriodMs = reportPeriodMs; + SDL_GameControllerSetSensorEnabled(m_GamepadState[controllerNumber].controller, SDL_SENSOR_ACCEL, reportRateHz ? SDL_TRUE : SDL_FALSE); + break; + + case LI_MOTION_TYPE_GYRO: + m_GamepadState[controllerNumber].gyroReportPeriodMs = reportPeriodMs; + SDL_GameControllerSetSensorEnabled(m_GamepadState[controllerNumber].controller, SDL_SENSOR_GYRO, reportRateHz ? SDL_TRUE : SDL_FALSE); + break; + } + } +#endif +} + QString SdlInputHandler::getUnmappedGamepads() { QString ret; diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 050ca438..415e7d34 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -19,6 +19,12 @@ struct GamepadState { SDL_TimerID mouseEmulationTimer; uint32_t lastStartDownTime; + uint8_t gyroReportPeriodMs; + uint32_t lastGyroEventTime; + + uint8_t accelReportPeriodMs; + uint32_t lastAccelEventTime; + int buttons; short lsX, lsY; short rsX, rsY; @@ -58,6 +64,12 @@ public: void handleControllerDeviceEvent(SDL_ControllerDeviceEvent* event); +#if SDL_VERSION_ATLEAST(2, 0, 14) + void handleControllerSensorEvent(SDL_ControllerSensorEvent* event); + + void handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent* event); +#endif + void handleJoystickArrivalEvent(SDL_JoyDeviceEvent* event); void sendText(QString& string); @@ -66,6 +78,8 @@ public: void rumbleTriggers(uint16_t controllerNumber, uint16_t leftTrigger, uint16_t rightTrigger); + void setMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz); + void handleTouchFingerEvent(SDL_TouchFingerEvent* event); int getAttachedGamepadMask(); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index c448f189..d23a0835 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -38,6 +38,7 @@ #define SDL_CODE_FLUSH_WINDOW_EVENT_BARRIER 100 #define SDL_CODE_GAMECONTROLLER_RUMBLE 101 #define SDL_CODE_GAMECONTROLLER_RUMBLE_TRIGGERS 102 +#define SDL_CODE_GAMECONTROLLER_SET_MOTION_EVENT_STATE 103 #include @@ -64,6 +65,7 @@ CONNECTION_LISTENER_CALLBACKS Session::k_ConnCallbacks = { Session::clConnectionStatusUpdate, Session::clSetHdrMode, Session::clRumbleTriggers, + Session::clSetMotionEventState, }; Session* Session::s_ActiveSession; @@ -228,6 +230,19 @@ void Session::clRumbleTriggers(uint16_t controllerNumber, uint16_t leftTrigger, SDL_PushEvent(&rumbleEvent); } +void Session::clSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) +{ + // We push an event for the main thread to handle in order to properly synchronize + // with the removal of game controllers that could result in our game controller + // going away during this callback. + SDL_Event setMotionEventStateEvent = {}; + setMotionEventStateEvent.type = SDL_USEREVENT; + setMotionEventStateEvent.user.code = SDL_CODE_GAMECONTROLLER_SET_MOTION_EVENT_STATE; + setMotionEventStateEvent.user.data1 = (void*)(uintptr_t)controllerNumber; + setMotionEventStateEvent.user.data2 = (void*)(uintptr_t)((motionType << 16) | reportRateHz); + SDL_PushEvent(&setMotionEventStateEvent); +} + bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds, SDL_Window* window, int videoFormat, int width, int height, int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder) @@ -1659,6 +1674,11 @@ void Session::execInternal() (uint16_t)((uintptr_t)event.user.data2 >> 16), (uint16_t)((uintptr_t)event.user.data2 & 0xFFFF)); break; + case SDL_CODE_GAMECONTROLLER_SET_MOTION_EVENT_STATE: + m_InputHandler->setMotionEventState((uint16_t)(uintptr_t)event.user.data1, + (uint8_t)((uintptr_t)event.user.data2 >> 16), + (uint16_t)((uintptr_t)event.user.data2 & 0xFFFF)); + break; default: SDL_assert(false); } @@ -1845,6 +1865,16 @@ void Session::execInternal() presence.runCallbacks(); m_InputHandler->handleControllerButtonEvent(&event.cbutton); break; +#if SDL_VERSION_ATLEAST(2, 0, 14) + case SDL_CONTROLLERSENSORUPDATE: + m_InputHandler->handleControllerSensorEvent(&event.csensor); + break; + case SDL_CONTROLLERTOUCHPADDOWN: + case SDL_CONTROLLERTOUCHPADUP: + case SDL_CONTROLLERTOUCHPADMOTION: + m_InputHandler->handleControllerTouchpadEvent(&event.ctouchpad); + break; +#endif case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEREMOVED: m_InputHandler->handleControllerDeviceEvent(&event.cdevice); diff --git a/app/streaming/session.h b/app/streaming/session.h index 83776f7a..e96ca761 100644 --- a/app/streaming/session.h +++ b/app/streaming/session.h @@ -127,6 +127,9 @@ private: static void clRumbleTriggers(uint16_t controllerNumber, uint16_t leftTrigger, uint16_t rightTrigger); + static + void clSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz); + static int arInit(int audioConfiguration, const POPUS_MULTISTREAM_CONFIGURATION opusConfig,