Implement gyro/accel and touchpad input using Sunshine extension

This commit is contained in:
Cameron Gutman 2023-06-18 16:08:32 -05:00
parent b945c8c2dc
commit 9af58af5e4
4 changed files with 125 additions and 0 deletions

View file

@ -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;

View file

@ -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();

View file

@ -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 <openssl/rand.h>
@ -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);

View file

@ -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,