mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-10-26 05:49:59 +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;
|
uint32_t enetPacketFlags;
|
||||||
uint8_t channelId;
|
uint8_t channelId;
|
||||||
|
|
||||||
|
int relMouseDeltaX;
|
||||||
|
int relMouseDeltaY;
|
||||||
|
|
||||||
// The union must be the last member since we abuse the NV_UNICODE_PACKET
|
// 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
|
// text field to store variable length data which gets split before being
|
||||||
// sent to the host.
|
// sent to the host.
|
||||||
@@ -79,19 +82,12 @@ typedef struct _PACKET_HOLDER {
|
|||||||
|
|
||||||
static PLT_MUTEX batchedInputMutex;
|
static PLT_MUTEX batchedInputMutex;
|
||||||
static PPACKET_HOLDER currentQueuedControllerPacket[MAX_GAMEPADS];
|
static PPACKET_HOLDER currentQueuedControllerPacket[MAX_GAMEPADS];
|
||||||
|
static PPACKET_HOLDER currentQueuedRelativeMousePacket;
|
||||||
|
static PPACKET_HOLDER currentQueuedAbsoluteMousePacket;
|
||||||
static struct {
|
static struct {
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
||||||
} currentGamepadSensorState[MAX_GAMEPADS][MAX_MOTION_EVENTS];
|
} 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
|
// Initializes the input stream
|
||||||
int initializeInputStream(void) {
|
int initializeInputStream(void) {
|
||||||
@@ -121,9 +117,9 @@ int initializeInputStream(void) {
|
|||||||
absCurrentPosX = absCurrentPosY = 0.5f;
|
absCurrentPosX = absCurrentPosY = 0.5f;
|
||||||
|
|
||||||
memset(currentQueuedControllerPacket, 0, sizeof(currentQueuedControllerPacket));
|
memset(currentQueuedControllerPacket, 0, sizeof(currentQueuedControllerPacket));
|
||||||
|
currentQueuedRelativeMousePacket = NULL;
|
||||||
|
currentQueuedAbsoluteMousePacket = NULL;
|
||||||
memset(currentGamepadSensorState, 0, sizeof(currentGamepadSensorState));
|
memset(currentGamepadSensorState, 0, sizeof(currentGamepadSensorState));
|
||||||
memset(¤tRelativeMouseState, 0, sizeof(currentRelativeMouseState));
|
|
||||||
memset(¤tAbsoluteMouseState, 0, sizeof(currentAbsoluteMouseState));
|
|
||||||
PltCreateMutex(&batchedInputMutex);
|
PltCreateMutex(&batchedInputMutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -158,6 +154,8 @@ void destroyInputStream(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(currentQueuedControllerPacket, 0, sizeof(currentQueuedControllerPacket));
|
memset(currentQueuedControllerPacket, 0, sizeof(currentQueuedControllerPacket));
|
||||||
|
currentQueuedRelativeMousePacket = NULL;
|
||||||
|
currentQueuedAbsoluteMousePacket = NULL;
|
||||||
PltDeleteMutex(&batchedInputMutex);
|
PltDeleteMutex(&batchedInputMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,13 +407,12 @@ static void inputSendThreadProc(void* context) {
|
|||||||
|
|
||||||
PltLockMutex(&batchedInputMutex);
|
PltLockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
int deltaX = currentRelativeMouseState.deltaX;
|
if (holder == currentQueuedRelativeMousePacket) {
|
||||||
int deltaY = currentRelativeMouseState.deltaY;
|
currentQueuedRelativeMousePacket = NULL;
|
||||||
currentRelativeMouseState.deltaX = 0;
|
}
|
||||||
currentRelativeMouseState.deltaY = 0;
|
|
||||||
|
|
||||||
// The state change is no longer pending
|
int deltaX = holder->relMouseDeltaX;
|
||||||
currentRelativeMouseState.dirty = false;
|
int deltaY = holder->relMouseDeltaY;
|
||||||
|
|
||||||
PltUnlockMutex(&batchedInputMutex);
|
PltUnlockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
@@ -480,20 +477,9 @@ static void inputSendThreadProc(void* context) {
|
|||||||
|
|
||||||
PltLockMutex(&batchedInputMutex);
|
PltLockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
// Populate the packet with the latest state
|
if (holder == currentQueuedAbsoluteMousePacket) {
|
||||||
holder->packet.mouseMoveAbs.x = BE16(currentAbsoluteMouseState.x);
|
currentQueuedAbsoluteMousePacket = NULL;
|
||||||
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);
|
PltUnlockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
@@ -760,6 +746,7 @@ int stopInputStream(void) {
|
|||||||
int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
||||||
PPACKET_HOLDER holder;
|
PPACKET_HOLDER holder;
|
||||||
int err;
|
int err;
|
||||||
|
bool enqueueHolder = false;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
return -2;
|
return -2;
|
||||||
@@ -771,20 +758,15 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
|||||||
|
|
||||||
PltLockMutex(&batchedInputMutex);
|
PltLockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
// Combine the previous deltas with the new one
|
// Switching to relative motion ends any pending absolute mouse batch
|
||||||
currentRelativeMouseState.deltaX += deltaX;
|
currentQueuedAbsoluteMousePacket = NULL;
|
||||||
currentRelativeMouseState.deltaY += deltaY;
|
|
||||||
|
|
||||||
// Queue a packet holder if this is the only pending relative mouse event
|
holder = currentQueuedRelativeMousePacket;
|
||||||
if (!currentRelativeMouseState.dirty) {
|
if (!holder) {
|
||||||
// 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;
|
|
||||||
PltUnlockMutex(&batchedInputMutex);
|
PltUnlockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
holder = allocatePacketHolder(0);
|
holder = allocatePacketHolder(0);
|
||||||
if (holder == NULL) {
|
if (holder == NULL) {
|
||||||
currentRelativeMouseState.dirty = false;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,21 +784,37 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
|||||||
holder->packet.mouseMoveRel.header.magic = LE32(MOUSE_MOVE_REL_MAGIC);
|
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);
|
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||||
if (err != LBQ_SUCCESS) {
|
if (err != LBQ_SUCCESS) {
|
||||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||||
Limelog("Input queue reached maximum size limit\n");
|
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
|
PltLockMutex(&batchedInputMutex);
|
||||||
currentRelativeMouseState.dirty = false;
|
if (currentQueuedRelativeMousePacket == holder) {
|
||||||
|
currentQueuedRelativeMousePacket = NULL;
|
||||||
|
}
|
||||||
|
PltUnlockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
|
freePacketHolder(holder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// There's already a packet holder queued to send this event
|
|
||||||
PltUnlockMutex(&batchedInputMutex);
|
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,6 +825,7 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY) {
|
|||||||
int LiSendMousePositionEvent(short x, short y, short referenceWidth, short referenceHeight) {
|
int LiSendMousePositionEvent(short x, short y, short referenceWidth, short referenceHeight) {
|
||||||
PPACKET_HOLDER holder;
|
PPACKET_HOLDER holder;
|
||||||
int err;
|
int err;
|
||||||
|
bool enqueueHolder = false;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
return -2;
|
return -2;
|
||||||
@@ -834,22 +833,15 @@ int LiSendMousePositionEvent(short x, short y, short referenceWidth, short refer
|
|||||||
|
|
||||||
PltLockMutex(&batchedInputMutex);
|
PltLockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
// Overwrite the previous mouse location with the new one
|
// Switching to absolute position ends any pending relative mouse batch
|
||||||
currentAbsoluteMouseState.x = x;
|
currentQueuedRelativeMousePacket = NULL;
|
||||||
currentAbsoluteMouseState.y = y;
|
|
||||||
currentAbsoluteMouseState.width = referenceWidth;
|
|
||||||
currentAbsoluteMouseState.height = referenceHeight;
|
|
||||||
|
|
||||||
// Queue a packet holder if this is the only pending absolute mouse event
|
holder = currentQueuedAbsoluteMousePacket;
|
||||||
if (!currentAbsoluteMouseState.dirty) {
|
if (!holder) {
|
||||||
// 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);
|
PltUnlockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
holder = allocatePacketHolder(0);
|
holder = allocatePacketHolder(0);
|
||||||
if (holder == NULL) {
|
if (holder == NULL) {
|
||||||
currentAbsoluteMouseState.dirty = false;
|
|
||||||
return -1;
|
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.header.magic = LE32(MOUSE_MOVE_ABS_MAGIC);
|
||||||
holder->packet.mouseMoveAbs.unused = 0;
|
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);
|
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||||
if (err != LBQ_SUCCESS) {
|
if (err != LBQ_SUCCESS) {
|
||||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||||
Limelog("Input queue reached maximum size limit\n");
|
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
|
PltLockMutex(&batchedInputMutex);
|
||||||
currentAbsoluteMouseState.dirty = false;
|
if (currentQueuedAbsoluteMousePacket == holder) {
|
||||||
|
currentQueuedAbsoluteMousePacket = NULL;
|
||||||
|
}
|
||||||
|
PltUnlockMutex(&batchedInputMutex);
|
||||||
|
|
||||||
|
freePacketHolder(holder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// There's already a packet holder queued to send this event
|
|
||||||
PltUnlockMutex(&batchedInputMutex);
|
|
||||||
err = 0;
|
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.header.magic = LE32(holder->packet.mouseButton.header.magic);
|
||||||
holder->packet.mouseButton.button = (uint8_t)button;
|
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);
|
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||||
if (err != LBQ_SUCCESS) {
|
if (err != LBQ_SUCCESS) {
|
||||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||||
|
|||||||
Reference in new issue
Block a user