From d247873adee6ac0b1ecfcee246d9513c009da9f5 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 28 May 2022 14:58:34 -0500 Subject: [PATCH] Add LiSendMouseMoveAsMousePositionEvent() function This is a useful option for Android and iOS where mouse acceleration is always enabled and mouse capture is the only feasible way to get mouse input. It can avoid double-acceleration when being used for remote desktop mouse mode. --- src/InputStream.c | 26 ++++++++++++++++++++++++++ src/Limelight.h | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/InputStream.c b/src/InputStream.c index 684f918..33b42d8 100644 --- a/src/InputStream.c +++ b/src/InputStream.c @@ -12,6 +12,11 @@ static LINKED_BLOCKING_QUEUE packetQueue; static LINKED_BLOCKING_QUEUE packetHolderFreeList; static PLT_THREAD inputSendThread; +static float absCurrentPosX; +static float absCurrentPosY; + +#define CLAMP(val, min, max) (((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val))) + #define MAX_INPUT_PACKET_SIZE 128 #define INPUT_STREAM_TIMEOUT_SEC 10 @@ -62,6 +67,9 @@ int initializeInputStream(void) { // GFE 3.15.0.164 seems to be the first release using NVVHCI for mouse/keyboard needsBatchedScroll = APP_VERSION_AT_LEAST(7, 1, 409); batchedScrollDelta = 0; + + // Start with the virtual mouse centered + absCurrentPosX = absCurrentPosY = 0.5f; return 0; } @@ -610,9 +618,27 @@ int LiSendMousePositionEvent(short x, short y, short referenceWidth, short refer freePacketHolder(holder); } + // This is not thread safe, but it's not a big deal because callers that want to + // use LiSendRelativeMotionAsMousePositionEvent() must not mix these function + // without synchronization (otherwise the state of the cursor on the host is + // undefined anyway). + absCurrentPosX = CLAMP(x, 0, referenceWidth - 1) / (float)(referenceWidth - 1); + absCurrentPosY = CLAMP(y, 0, referenceHeight - 1) / (float)(referenceHeight - 1); + return err; } +// Send a relative motion event using absolute position to the streaming machine +int LiSendMouseMoveAsMousePositionEvent(short deltaX, short deltaY, short referenceWidth, short referenceHeight) { + // Convert the current position to be relative to the provided reference dimensions + short oldPositionX = (short)(absCurrentPosX * referenceWidth); + short oldPositionY = (short)(absCurrentPosY * referenceHeight); + + return LiSendMousePositionEvent(CLAMP(oldPositionX + deltaX, 0, referenceWidth), + CLAMP(oldPositionY + deltaY, 0, referenceHeight), + referenceWidth, referenceHeight); +} + // Send a mouse button event to the streaming machine int LiSendMouseButtonEvent(char action, int button) { PPACKET_HOLDER holder; diff --git a/src/Limelight.h b/src/Limelight.h index 37de7dc..73f473e 100644 --- a/src/Limelight.h +++ b/src/Limelight.h @@ -509,6 +509,25 @@ int LiSendMouseMoveEvent(short deltaX, short deltaY); // referenceWidth and referenceHeight to your window width and height. int LiSendMousePositionEvent(short x, short y, short referenceWidth, short referenceHeight); +// This function queues a mouse position update event to be sent to the remote server, so +// all of the limitations of LiSendMousePositionEvent() mentioned above apply here too! +// +// This function behaves like a combination of LiSendMouseMoveEvent() and LiSendMousePositionEvent() +// in that it sends a relative motion event, however it sends this data as an absolute position +// based on the computed position of a virtual client cursor which is "moved" any time that +// LiSendMousePositionEvent() or LiSendMouseMoveAsMousePositionEvent() is called. As a result +// of this internal virtual cursor state, callers must ensure LiSendMousePositionEvent() and +// LiSendMouseMoveAsMousePositionEvent() are not called concurrently! +// +// The big advantage of this function is that it allows callers to avoid mouse acceleration that +// would otherwise affect motion when using LiSendMouseMoveEvent(). The downside is that it has the +// same game compatibility issues as LiSendMousePositionEvent(). +// +// This function can be useful when mouse capture is the only feasible way to receive mouse input, +// like on Android or iOS, and the OS cannot provide raw unaccelerated mouse motion when capturing. +// Using this function avoids double-acceleration in cases when the client motion is also accelerated. +int LiSendMouseMoveAsMousePositionEvent(short deltaX, short deltaY, short referenceWidth, short referenceHeight); + // This function queues a mouse button event to be sent to the remote server. #define BUTTON_ACTION_PRESS 0x07 #define BUTTON_ACTION_RELEASE 0x08