mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-17 08:55:48 +00:00
Add support for controller and mouse movement batching
This commit is contained in:
parent
626cbbf951
commit
a6cb892a28
@ -94,6 +94,35 @@ void destroyInputStream(void) {
|
||||
initialized = 0;
|
||||
}
|
||||
|
||||
// Checks if values are compatible with controller batching
|
||||
static int checkDirs(short currentVal, short newVal, int* dir) {
|
||||
if (currentVal == newVal) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// We want to send a new packet if we've now zeroed an axis
|
||||
if (newVal == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*dir == 0) {
|
||||
if (newVal < currentVal) {
|
||||
*dir = -1;
|
||||
}
|
||||
else {
|
||||
*dir = 1;
|
||||
}
|
||||
}
|
||||
else if (*dir == -1) {
|
||||
return newVal < currentVal;
|
||||
}
|
||||
else if (newVal < currentVal) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define OAES_DATA_OFFSET 32
|
||||
|
||||
/* Input thread proc */
|
||||
@ -112,6 +141,106 @@ static void inputSendThreadProc(void* context) {
|
||||
listenerCallbacks->connectionTerminated(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a multi-controller packet we can do batching
|
||||
if (holder->packet.multiController.header.packetType == htonl(PACKET_TYPE_MULTI_CONTROLLER)) {
|
||||
PPACKET_HOLDER controllerBatchHolder;
|
||||
PNV_MULTI_CONTROLLER_PACKET origPkt;
|
||||
int dirs[6];
|
||||
|
||||
origPkt = &holder->packet.multiController;
|
||||
for (;;) {
|
||||
PNV_MULTI_CONTROLLER_PACKET newPkt;
|
||||
|
||||
// Peek at the next packet
|
||||
if (LbqPeekQueueElement(&packetQueue, (void**)&controllerBatchHolder) != LBQ_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If it's not a controller packet, we're done
|
||||
if (controllerBatchHolder->packet.multiController.header.packetType != htonl(PACKET_TYPE_MULTI_CONTROLLER)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if it's able to be batched
|
||||
newPkt = &controllerBatchHolder->packet.multiController;
|
||||
if (newPkt->buttonFlags != origPkt->buttonFlags ||
|
||||
newPkt->controllerNumber != origPkt->controllerNumber ||
|
||||
!checkDirs(origPkt->leftTrigger, newPkt->leftTrigger, &dirs[0]) ||
|
||||
!checkDirs(origPkt->rightTrigger, newPkt->rightTrigger, &dirs[1]) ||
|
||||
!checkDirs(origPkt->leftStickX, newPkt->leftStickX, &dirs[2]) ||
|
||||
!checkDirs(origPkt->leftStickY, newPkt->leftStickY, &dirs[3]) ||
|
||||
!checkDirs(origPkt->rightStickX, newPkt->rightStickX, &dirs[4]) ||
|
||||
!checkDirs(origPkt->rightStickY, newPkt->rightStickY, &dirs[5])) {
|
||||
// Batching not allowed
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the batchable controller packet
|
||||
if (LbqPollQueueElement(&packetQueue, (void**)&controllerBatchHolder) != LBQ_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the original packet
|
||||
origPkt->leftTrigger = newPkt->leftTrigger;
|
||||
origPkt->rightTrigger = newPkt->rightTrigger;
|
||||
origPkt->leftStickX = newPkt->leftStickX;
|
||||
origPkt->leftStickY = newPkt->leftStickY;
|
||||
origPkt->rightStickX = newPkt->rightStickX;
|
||||
origPkt->rightStickY = newPkt->rightStickY;
|
||||
|
||||
// Free the batched packet holder
|
||||
free(controllerBatchHolder);
|
||||
}
|
||||
}
|
||||
// If it's a mouse move packet, we can also do batching
|
||||
else if (holder->packet.mouseMove.header.packetType == htonl(PACKET_TYPE_MOUSE_MOVE)) {
|
||||
PPACKET_HOLDER mouseBatchHolder;
|
||||
int totalDeltaX = htons(holder->packet.mouseMove.deltaX);
|
||||
int totalDeltaY = htons(holder->packet.mouseMove.deltaY);
|
||||
|
||||
for (;;) {
|
||||
int partialDeltaX;
|
||||
int partialDeltaY;
|
||||
|
||||
// Peek at the next packet
|
||||
if (LbqPeekQueueElement(&packetQueue, (void**)&mouseBatchHolder) != LBQ_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If it's not a mouse move packet, we're done
|
||||
if (mouseBatchHolder->packet.mouseMove.header.packetType != htonl(PACKET_TYPE_MOUSE_MOVE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
partialDeltaX = htons(mouseBatchHolder->packet.mouseMove.deltaX);
|
||||
partialDeltaY = htons(mouseBatchHolder->packet.mouseMove.deltaY);
|
||||
|
||||
// Check for overflow
|
||||
if (partialDeltaX + totalDeltaX > INT16_MAX ||
|
||||
partialDeltaX + totalDeltaX < INT16_MIN ||
|
||||
partialDeltaY + totalDeltaY > INT16_MAX ||
|
||||
partialDeltaY + totalDeltaY < INT16_MIN) {
|
||||
// Total delta would overflow our 16-bit short
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the batchable mouse move packet
|
||||
if (LbqPollQueueElement(&packetQueue, (void**)&mouseBatchHolder) != LBQ_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
totalDeltaX += partialDeltaX;
|
||||
totalDeltaY += partialDeltaY;
|
||||
|
||||
// Free the batched packet holder
|
||||
free(mouseBatchHolder);
|
||||
}
|
||||
|
||||
// Update the original packet
|
||||
holder->packet.mouseMove.deltaX = htons((short)totalDeltaX);
|
||||
holder->packet.mouseMove.deltaY = htons((short)totalDeltaY);
|
||||
}
|
||||
|
||||
encryptedSize = sizeof(encryptedBuffer);
|
||||
err = oaes_encrypt(oaesContext, (const unsigned char*) &holder->packet, holder->packetLength,
|
||||
|
@ -85,6 +85,60 @@ int LbqOfferQueueItem(PLINKED_BLOCKING_QUEUE queueHead, void* data, PLINKED_BLOC
|
||||
return LBQ_SUCCESS;
|
||||
}
|
||||
|
||||
// This must be synchronized with LbqFlushQueueItems by the caller
|
||||
int LbqPeekQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) {
|
||||
if (queueHead->head == NULL) {
|
||||
return LBQ_NO_ELEMENT;
|
||||
}
|
||||
|
||||
PltLockMutex(&queueHead->mutex);
|
||||
|
||||
if (queueHead->head == NULL) {
|
||||
PltUnlockMutex(&queueHead->mutex);
|
||||
return LBQ_NO_ELEMENT;
|
||||
}
|
||||
|
||||
*data = queueHead->head->data;
|
||||
|
||||
PltUnlockMutex(&queueHead->mutex);
|
||||
|
||||
return LBQ_SUCCESS;
|
||||
}
|
||||
|
||||
int LbqPollQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) {
|
||||
PLINKED_BLOCKING_QUEUE_ENTRY entry;
|
||||
|
||||
if (queueHead->head == NULL) {
|
||||
return LBQ_NO_ELEMENT;
|
||||
}
|
||||
|
||||
PltLockMutex(&queueHead->mutex);
|
||||
|
||||
if (queueHead->head == NULL) {
|
||||
PltUnlockMutex(&queueHead->mutex);
|
||||
return LBQ_NO_ELEMENT;
|
||||
}
|
||||
|
||||
entry = queueHead->head;
|
||||
queueHead->head = entry->flink;
|
||||
queueHead->currentSize--;
|
||||
if (queueHead->head == NULL) {
|
||||
LC_ASSERT(queueHead->currentSize == 0);
|
||||
queueHead->tail = NULL;
|
||||
PltClearEvent(&queueHead->containsDataEvent);
|
||||
}
|
||||
else {
|
||||
LC_ASSERT(queueHead->currentSize != 0);
|
||||
queueHead->head->blink = NULL;
|
||||
}
|
||||
|
||||
*data = entry->data;
|
||||
|
||||
PltUnlockMutex(&queueHead->mutex);
|
||||
|
||||
return LBQ_SUCCESS;
|
||||
}
|
||||
|
||||
int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) {
|
||||
PLINKED_BLOCKING_QUEUE_ENTRY entry;
|
||||
int err;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define LBQ_SUCCESS 0
|
||||
#define LBQ_INTERRUPTED 1
|
||||
#define LBQ_BOUND_EXCEEDED 2
|
||||
#define LBQ_NO_ELEMENT 3
|
||||
|
||||
typedef struct _LINKED_BLOCKING_QUEUE_ENTRY {
|
||||
struct _LINKED_BLOCKING_QUEUE_ENTRY *flink;
|
||||
@ -25,5 +26,7 @@ typedef struct _LINKED_BLOCKING_QUEUE {
|
||||
int LbqInitializeLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead, int sizeBound);
|
||||
int LbqOfferQueueItem(PLINKED_BLOCKING_QUEUE queueHead, void* data, PLINKED_BLOCKING_QUEUE_ENTRY entry);
|
||||
int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data);
|
||||
int LbqPollQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data);
|
||||
int LbqPeekQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data);
|
||||
PLINKED_BLOCKING_QUEUE_ENTRY LbqDestroyLinkedBlockingQueue(PLINKED_BLOCKING_QUEUE queueHead);
|
||||
PLINKED_BLOCKING_QUEUE_ENTRY LbqFlushQueueItems(PLINKED_BLOCKING_QUEUE queueHead);
|
||||
|
Loading…
x
Reference in New Issue
Block a user