diff --git a/src/ControlStream.c b/src/ControlStream.c index d2af2d4..93c26ca 100644 --- a/src/ControlStream.c +++ b/src/ControlStream.c @@ -85,6 +85,8 @@ static PPLT_CRYPTO_CONTEXT decryptionCtx; #define IDX_RUMBLE_DATA 6 #define IDX_TERMINATION 7 #define IDX_HDR_INFO 8 +#define IDX_RUMBLE_TRIGGER_DATA 9 +#define IDX_SET_MOTION_EVENT 10 #define CONTROL_STREAM_TIMEOUT_SEC 10 #define CONTROL_STREAM_LINGER_TIMEOUT_SEC 2 @@ -99,6 +101,8 @@ static const short packetTypesGen3[] = { -1, // Rumble data (unused) -1, // Termination (unused) -1, // HDR mode (unused) + -1, // Rumble triggers (unused) + -1, // Set motion event (unused) }; static const short packetTypesGen4[] = { 0x0606, // Request IDR frame @@ -110,6 +114,8 @@ static const short packetTypesGen4[] = { -1, // Rumble data (unused) -1, // Termination (unused) -1, // HDR mode (unused) + -1, // Rumble triggers (unused) + -1, // Set motion event (unused) }; static const short packetTypesGen5[] = { 0x0305, // Start A @@ -121,6 +127,8 @@ static const short packetTypesGen5[] = { -1, // Rumble data (unused) -1, // Termination (unused) -1, // HDR mode (unknown) + -1, // Rumble triggers (unused) + -1, // Set motion event (unused) }; static const short packetTypesGen7[] = { 0x0305, // Start A @@ -132,6 +140,8 @@ static const short packetTypesGen7[] = { 0x010b, // Rumble data 0x0100, // Termination 0x010e, // HDR mode + -1, // Rumble triggers (unused) + -1, // Set motion event (unused) }; static const short packetTypesGen7Enc[] = { 0x0302, // Request IDR frame @@ -143,6 +153,8 @@ static const short packetTypesGen7Enc[] = { 0x010b, // Rumble data 0x0109, // Termination (extended) 0x010e, // HDR mode + 0x5500, // Rumble triggers (Sunshine protocol extension) + 0x5501, // Set motion event (Sunshine protocol extension) }; static const char requestIdrFrameGen3[] = { 0, 0 }; @@ -899,6 +911,36 @@ static void controlReceiveThreadFunc(void* context) { ListenerCallbacks.rumble(controllerNumber, lowFreqRumble, highFreqRumble); } + else if (ctlHdr->type == packetTypes[IDX_RUMBLE_TRIGGER_DATA]) { + BYTE_BUFFER bb; + + BbInitializeWrappedBuffer(&bb, (char*)ctlHdr, sizeof(*ctlHdr), packetLength - sizeof(*ctlHdr), BYTE_ORDER_LITTLE); + + uint16_t controllerNumber; + uint16_t leftTriggerMotor; + uint16_t rightTriggerMotor; + + BbGet16(&bb, &controllerNumber); + BbGet16(&bb, &leftTriggerMotor); + BbGet16(&bb, &rightTriggerMotor); + + ListenerCallbacks.rumbleTriggers(controllerNumber, leftTriggerMotor, rightTriggerMotor); + } + else if (ctlHdr->type == packetTypes[IDX_SET_MOTION_EVENT]) { + BYTE_BUFFER bb; + + BbInitializeWrappedBuffer(&bb, (char*)ctlHdr, sizeof(*ctlHdr), packetLength - sizeof(*ctlHdr), BYTE_ORDER_LITTLE); + + uint16_t controllerNumber; + uint16_t reportRateHz; + uint8_t motionType; + + BbGet16(&bb, &controllerNumber); + BbGet16(&bb, &reportRateHz); + BbGet8(&bb, &motionType); + + ListenerCallbacks.setMotionEventState(controllerNumber, motionType, reportRateHz); + } else if (ctlHdr->type == packetTypes[IDX_HDR_INFO]) { BYTE_BUFFER bb; uint8_t enableByte; diff --git a/src/FakeCallbacks.c b/src/FakeCallbacks.c index d8cada4..795871d 100644 --- a/src/FakeCallbacks.c +++ b/src/FakeCallbacks.c @@ -37,6 +37,8 @@ static void fakeClLogMessage(const char* format, ...) {} static void fakeClRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor) {} static void fakeClConnectionStatusUpdate(int connectionStatus) {} static void fakeClSetHdrMode(bool enabled) {} +static void fakeClRumbleTriggers(uint16_t controllerNumber, uint16_t leftTriggerMotor, uint16_t rightTriggerMotor) {} +static void fakeClSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz); static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = { .stageStarting = fakeClStageStarting, @@ -48,6 +50,8 @@ static CONNECTION_LISTENER_CALLBACKS fakeClCallbacks = { .rumble = fakeClRumble, .connectionStatusUpdate = fakeClConnectionStatusUpdate, .setHdrMode = fakeClSetHdrMode, + .rumbleTriggers = fakeClRumbleTriggers, + .setMotionEventState = fakeClSetMotionEventState, }; void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_RENDERER_CALLBACKS* arCallbacks, @@ -126,5 +130,11 @@ void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_REND if ((*clCallbacks)->setHdrMode == NULL) { (*clCallbacks)->setHdrMode = fakeClSetHdrMode; } + if ((*clCallbacks)->rumbleTriggers == NULL) { + (*clCallbacks)->rumbleTriggers = fakeClRumbleTriggers; + } + if ((*clCallbacks)->setMotionEventState == NULL) { + (*clCallbacks)->setMotionEventState = fakeClSetMotionEventState; + } } } diff --git a/src/Limelight.h b/src/Limelight.h index 19de334..d25a7b6 100644 --- a/src/Limelight.h +++ b/src/Limelight.h @@ -454,6 +454,17 @@ typedef void(*ConnListenerConnectionStatusUpdate)(int connectionStatus); // if enableHdr is false in the stream configuration. typedef void(*ConnListenerSetHdrMode)(bool hdrEnabled); +// This callback is invoked to rumble a gamepad's triggers. For more details, +// see the comment above on ConnListenerRumble(). +typedef void(*ConnListenerRumbleTriggers)(uint16_t controllerNumber, uint16_t leftTriggerMotor, uint16_t rightTriggerMotor); + +// This callback is invoked to notify the client that the host would like motion +// sensor reports for the specified gamepad (see LiSendControllerMotionEvent()) +// at the specified reporting rate (or as close as possible). +// +// If reportRateHz is 0, the host is asking for motion event reporting to stop. +typedef void(*ConnListenerSetMotionEventState)(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz); + typedef struct _CONNECTION_LISTENER_CALLBACKS { ConnListenerStageStarting stageStarting; ConnListenerStageComplete stageComplete; @@ -464,6 +475,8 @@ typedef struct _CONNECTION_LISTENER_CALLBACKS { ConnListenerRumble rumble; ConnListenerConnectionStatusUpdate connectionStatusUpdate; ConnListenerSetHdrMode setHdrMode; + ConnListenerRumbleTriggers rumbleTriggers; + ConnListenerSetMotionEventState setMotionEventState; } CONNECTION_LISTENER_CALLBACKS, *PCONNECTION_LISTENER_CALLBACKS; // Use this function to zero the connection callbacks when allocated on the stack or heap