mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-10-26 13:59:58 +00:00
End mouse motion batches on mouse button events
This commit is contained in:
1 parent
f1cca2dd6b
commit
421bd74e01
1 file changed
+84
-63
+84
-63
@@ -53,6 +53,9 @@ typedef struct _PACKET_HOLDER {
|
||||
uint32_t enetPacketFlags;
|
||||
uint8_t channelId;
|
||||
|
||||
int relMouseDeltaX;
|
||||
int relMouseDeltaY;
|
||||
|
||||
// The union must be the last member since we abuse the NV_UNICODE_PACKET
|
||||
// text field to store variable length data which gets split before being
|
||||
// sent to the host.
|
||||
@@ -79,19 +82,12 @@ typedef struct _PACKET_HOLDER {
|
||||
|
||||
static PLT_MUTEX batchedInputMutex;
|
||||
static PPACKET_HOLDER currentQueuedControllerPacket[MAX_GAMEPADS];
|
||||
static PPACKET_HOLDER currentQueuedRelativeMousePacket;
|
||||
static PPACKET_HOLDER currentQueuedAbsoluteMousePacket;
|
||||
static struct {
|
||||
float x, y, z;
|
||||
bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
||||
} currentGamepadSensorState[MAX_GAMEPADS][MAX_MOTION_EVENTS];
|
||||
static struct {
|
||||
int deltaX, deltaY;
|
||||
bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
||||
} currentRelativeMouseState;
|
||||
static struct {
|
||||
int x, y;
|
||||
int width, height;
|
||||
bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
||||
} currentAbsoluteMouseState;
|
||||
|
||||
// Initializes the input stream
|
||||
int initializeInputStream(void) {
|
||||
@@ -121,9 +117,9 @@ int initializeInputStream(void) {
|
||||
absCurrentPosX = absCurrentPosY = 0.5f;
|
||||
|
||||
memset(currentQueuedControllerPacket, 0, sizeof(currentQueuedControllerPacket));
|
||||
currentQueuedRelativeMousePacket = NULL;
|
||||
currentQueuedAbsoluteMousePacket = NULL;
|
||||
memset(currentGamepadSensorState, 0, sizeof(currentGamepadSensorState));
|
||||
memset(¤tRelativeMouseState, 0, sizeof(currentRelativeMouseState));
|
||||
memset(¤tAbsoluteMouseState, 0, sizeof(currentAbsoluteMouseState));
|
||||
PltCreateMutex(&batchedInputMutex);
|
||||
|
||||
return 0;
|
||||
@@ -158,6 +154,8 @@ void destroyInputStream(void) {
|
||||
}
|
||||
|
||||
memset(currentQueuedControllerPacket, 0, sizeof(currentQueuedControllerPacket));
|
||||
currentQueuedRelativeMousePacket = NULL;
|
||||
currentQueuedAbsoluteMousePacket = NULL;
|
||||
PltDeleteMutex(&batchedInputMutex);
|
||||
}
|
||||
|
||||
@@ -409,13 +407,12 @@ static void inputSendThreadProc(void* context) {
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
|
||||
int deltaX = currentRelativeMouseState.deltaX;
|
||||
int deltaY = currentRelativeMouseState.deltaY;
|
||||
currentRelativeMouseState.deltaX = 0;
|
||||
currentRelativeMouseState.deltaY = 0;
|
||||
if (holder == currentQueuedRelativeMousePacket) {
|
||||
currentQueuedRelativeMousePacket = NULL;
|
||||
}
|
||||
|
||||
// The state change is no longer pending
|
||||
currentRelativeMouseState.dirty = false;
|
||||
int deltaX = holder->relMouseDeltaX;
|
||||
int deltaY = holder->relMouseDeltaY;
|
||||
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
@@ -480,20 +477,9 @@ static void inputSendThreadProc(void* context) {
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
|
||||
// Populate the packet with the latest state
|
||||
holder->packet.mouseMoveAbs.x = BE16(currentAbsoluteMouseState.x);
|
||||
holder->packet.mouseMoveAbs.y = BE16(currentAbsoluteMouseState.y);
|
||||
|
||||
// There appears to be a rounding error in GFE's scaling calculation which prevents
|
||||
// the cursor from reaching the far edge of the screen when streaming at smaller
|
||||
// resolutions with a higher desktop resolution (like streaming 720p with a desktop
|
||||
// resolution of 1080p, or streaming 720p/1080p with a desktop resolution of 4K).
|
||||
// Subtracting one from the reference dimensions seems to work around this issue.
|
||||
holder->packet.mouseMoveAbs.width = BE16(currentAbsoluteMouseState.width - 1);
|
||||
holder->packet.mouseMoveAbs.height = BE16(currentAbsoluteMouseState.height - 1);
|
||||
|
||||
// The state change is no longer pending
|
||||
currentAbsoluteMouseState.dirty = false;
|
||||
if (holder == currentQueuedAbsoluteMousePacket) {
|
||||
currentQueuedAbsoluteMousePacket = NULL;
|
||||
}
|
||||
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
@@ -760,6 +746,7 @@ int stopInputStream(void) {
|
||||
int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
||||
PPACKET_HOLDER holder;
|
||||
int err;
|
||||
bool enqueueHolder = false;
|
||||
|
||||
if (!initialized) {
|
||||
return -2;
|
||||
@@ -771,20 +758,15 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
|
||||
// Combine the previous deltas with the new one
|
||||
currentRelativeMouseState.deltaX += deltaX;
|
||||
currentRelativeMouseState.deltaY += deltaY;
|
||||
// Switching to relative motion ends any pending absolute mouse batch
|
||||
currentQueuedAbsoluteMousePacket = NULL;
|
||||
|
||||
// Queue a packet holder if this is the only pending relative mouse event
|
||||
if (!currentRelativeMouseState.dirty) {
|
||||
// Set the dirty flag to claim ownership of inserting the packet holder
|
||||
// and unlock to allow other threads to enqueue or process input.
|
||||
currentRelativeMouseState.dirty = true;
|
||||
holder = currentQueuedRelativeMousePacket;
|
||||
if (!holder) {
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
holder = allocatePacketHolder(0);
|
||||
if (holder == NULL) {
|
||||
currentRelativeMouseState.dirty = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -802,21 +784,37 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
||||
holder->packet.mouseMoveRel.header.magic = LE32(MOUSE_MOVE_REL_MAGIC);
|
||||
}
|
||||
|
||||
// Remaining fields are set in the input thread based on the latest currentRelativeMouseState values
|
||||
holder->relMouseDeltaX = 0;
|
||||
holder->relMouseDeltaY = 0;
|
||||
|
||||
enqueueHolder = true;
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
currentQueuedRelativeMousePacket = holder;
|
||||
}
|
||||
|
||||
// Combine previous deltas with the new one
|
||||
holder->relMouseDeltaX += deltaX;
|
||||
holder->relMouseDeltaY += deltaY;
|
||||
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
if (enqueueHolder) {
|
||||
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||
if (err != LBQ_SUCCESS) {
|
||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||
Limelog("Input queue reached maximum size limit\n");
|
||||
freePacketHolder(holder);
|
||||
|
||||
// We weren't able to insert the entry, so let the next call try again
|
||||
currentRelativeMouseState.dirty = false;
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
if (currentQueuedRelativeMousePacket == holder) {
|
||||
currentQueuedRelativeMousePacket = NULL;
|
||||
}
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
freePacketHolder(holder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There's already a packet holder queued to send this event
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
err = 0;
|
||||
}
|
||||
|
||||
@@ -827,6 +825,7 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
||||
int LiSendMousePositionEvent(short x, short y, short referenceWidth, short referenceHeight) {
|
||||
PPACKET_HOLDER holder;
|
||||
int err;
|
||||
bool enqueueHolder = false;
|
||||
|
||||
if (!initialized) {
|
||||
return -2;
|
||||
@@ -834,22 +833,15 @@ int LiSendMousePositionEvent(short x, short y, short referenceWidth, short refer
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
|
||||
// Overwrite the previous mouse location with the new one
|
||||
currentAbsoluteMouseState.x = x;
|
||||
currentAbsoluteMouseState.y = y;
|
||||
currentAbsoluteMouseState.width = referenceWidth;
|
||||
currentAbsoluteMouseState.height = referenceHeight;
|
||||
// Switching to absolute position ends any pending relative mouse batch
|
||||
currentQueuedRelativeMousePacket = NULL;
|
||||
|
||||
// Queue a packet holder if this is the only pending absolute mouse event
|
||||
if (!currentAbsoluteMouseState.dirty) {
|
||||
// Set the dirty flag to claim ownership of inserting the packet holder
|
||||
// and unlock to allow other threads to enqueue or process input.
|
||||
currentAbsoluteMouseState.dirty = true;
|
||||
holder = currentQueuedAbsoluteMousePacket;
|
||||
if (!holder) {
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
holder = allocatePacketHolder(0);
|
||||
if (holder == NULL) {
|
||||
currentAbsoluteMouseState.dirty = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -862,21 +854,42 @@ int LiSendMousePositionEvent(short x, short y, short referenceWidth, short refer
|
||||
holder->packet.mouseMoveAbs.header.magic = LE32(MOUSE_MOVE_ABS_MAGIC);
|
||||
holder->packet.mouseMoveAbs.unused = 0;
|
||||
|
||||
// Remaining fields are set in the input thread based on the latest currentAbsoluteMouseState values
|
||||
enqueueHolder = true;
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
currentQueuedAbsoluteMousePacket = holder;
|
||||
}
|
||||
|
||||
// Overwrite the previous mouse location with the new one
|
||||
holder->packet.mouseMoveAbs.x = BE16(x);
|
||||
holder->packet.mouseMoveAbs.y = BE16(y);
|
||||
|
||||
// There appears to be a rounding error in GFE's scaling calculation which prevents
|
||||
// the cursor from reaching the far edge of the screen when streaming at smaller
|
||||
// resolutions with a higher desktop resolution (like streaming 720p with a desktop
|
||||
// resolution of 1080p, or streaming 720p/1080p with a desktop resolution of 4K).
|
||||
// Subtracting one from the reference dimensions seems to work around this issue.
|
||||
holder->packet.mouseMoveAbs.width = BE16(referenceWidth - 1);
|
||||
holder->packet.mouseMoveAbs.height = BE16(referenceHeight - 1);
|
||||
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
if (enqueueHolder) {
|
||||
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||
if (err != LBQ_SUCCESS) {
|
||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||
Limelog("Input queue reached maximum size limit\n");
|
||||
freePacketHolder(holder);
|
||||
|
||||
// We weren't able to insert the entry, so let the next call try again
|
||||
currentAbsoluteMouseState.dirty = false;
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
if (currentQueuedAbsoluteMousePacket == holder) {
|
||||
currentQueuedAbsoluteMousePacket = NULL;
|
||||
}
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
freePacketHolder(holder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There's already a packet holder queued to send this event
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
err = 0;
|
||||
}
|
||||
|
||||
@@ -925,6 +938,14 @@ int LiSendMouseButtonEvent(char action, int button) {
|
||||
holder->packet.mouseButton.header.magic = LE32(holder->packet.mouseButton.header.magic);
|
||||
holder->packet.mouseButton.button = (uint8_t)button;
|
||||
|
||||
// End any current mouse motion batches so that mouse movements that occurred
|
||||
// before this button event are sent before it, and mouse movements that occur
|
||||
// after this button event are sent after it.
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
currentQueuedRelativeMousePacket = NULL;
|
||||
currentQueuedAbsoluteMousePacket = NULL;
|
||||
PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||
if (err != LBQ_SUCCESS) {
|
||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||
|
||||
Reference in new issue
Block a user