vdi-cloud/terminal/moonlight/patches/0002-vdi-absolute-click-barrier.patch

144 lines
5.9 KiB
Diff

--- a/src/InputStream.c
+++ b/src/InputStream.c
@@ -86,11 +86,16 @@
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;
+// Only this packet may absorb newer positions. A button event seals the batch.
+static PPACKET_HOLDER currentQueuedAbsoluteMousePacket;
+
+static void latchAbsoluteMousePacket(PPACKET_HOLDER holder) {
+ PltLockMutex(&batchedInputMutex);
+ if (currentQueuedAbsoluteMousePacket == holder) {
+ currentQueuedAbsoluteMousePacket = NULL;
+ }
+ PltUnlockMutex(&batchedInputMutex);
+}
// Initializes the input stream
int initializeInputStream(void) {
@@ -120,7 +125,7 @@
memset(currentGamepadSensorState, 0, sizeof(currentGamepadSensorState));
memset(&currentRelativeMouseState, 0, sizeof(currentRelativeMouseState));
- memset(&currentAbsoluteMouseState, 0, sizeof(currentAbsoluteMouseState));
+ currentQueuedAbsoluteMousePacket = NULL;
PltCreateMutex(&batchedInputMutex);
return 0;
@@ -444,24 +449,9 @@
now = PltGetMillis();
}
- 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;
-
- PltUnlockMutex(&batchedInputMutex);
+ // Payload was filled by the producer under the same mutex. Latch
+ // only our packet; a later batch may already be queued after a click.
+ latchAbsoluteMousePacket(holder);
lastMousePacketTime = now;
}
@@ -780,52 +770,37 @@
}
PltLockMutex(&batchedInputMutex);
-
- // Overwrite the previous mouse location with the new one
- currentAbsoluteMouseState.x = x;
- currentAbsoluteMouseState.y = y;
- currentAbsoluteMouseState.width = referenceWidth;
- currentAbsoluteMouseState.height = referenceHeight;
-
- // 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;
- PltUnlockMutex(&batchedInputMutex);
-
+ holder = currentQueuedAbsoluteMousePacket;
+ bool newPacket = holder == NULL;
+ if (newPacket) {
holder = allocatePacketHolder(0);
if (holder == NULL) {
- currentAbsoluteMouseState.dirty = false;
+ PltUnlockMutex(&batchedInputMutex);
return -1;
}
-
holder->channelId = CTRL_CHANNEL_MOUSE;
-
- // TODO: Send this as unreliable sequenced when we have a delayed reliable retransmission thread
holder->enetPacketFlags = ENET_PACKET_FLAG_RELIABLE;
-
holder->packet.mouseMoveAbs.header.size = BE32(sizeof(NV_ABS_MOUSE_MOVE_PACKET) - sizeof(uint32_t));
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
-
+ }
+ holder->packet.mouseMoveAbs.x = BE16(x);
+ holder->packet.mouseMoveAbs.y = BE16(y);
+ // Preserve upstream's far-edge rounding workaround.
+ holder->packet.mouseMoveAbs.width = BE16(referenceWidth - 1);
+ holder->packet.mouseMoveAbs.height = BE16(referenceHeight - 1);
+ err = 0;
+ if (newPacket) {
+ currentQueuedAbsoluteMousePacket = holder;
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
if (err != LBQ_SUCCESS) {
+ currentQueuedAbsoluteMousePacket = NULL;
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;
- }
- }
- else {
- // There's already a packet holder queued to send this event
- PltUnlockMutex(&batchedInputMutex);
- err = 0;
- }
+ }
+ }
+ PltUnlockMutex(&batchedInputMutex);
// This is not thread safe, but it's not a big deal because callers that want to
// use LiSendRelativeMotionAsMousePositionEvent() must not mix these function
@@ -872,7 +847,11 @@
holder->packet.mouseButton.header.magic = LE32(holder->packet.mouseButton.header.magic);
holder->packet.mouseButton.button = (uint8_t)button;
+ PltLockMutex(&batchedInputMutex);
+ // Do not let a later position overwrite the move preceding this click.
+ currentQueuedAbsoluteMousePacket = NULL;
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
+ PltUnlockMutex(&batchedInputMutex);
if (err != LBQ_SUCCESS) {
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
Limelog("Input queue reached maximum size limit\n");