[server,shadow] implement relative mouse support

This commit is contained in:
akallabeth
2025-03-27 09:19:38 +01:00
parent 7471d11875
commit 87683746a5
5 changed files with 138 additions and 3 deletions

View File

@@ -92,6 +92,10 @@ extern "C"
UINT16 code);
typedef BOOL (*pfnShadowMouseEvent)(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
UINT16 flags, UINT16 x, UINT16 y);
typedef BOOL (*pfnShadowRelMouseEvent)(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
UINT16 flags, INT16 xDelta,
INT16 yDelta); /** @since version 3.15.0 */
typedef BOOL (*pfnShadowExtendedMouseEvent)(rdpShadowSubsystem* subsystem,
rdpShadowClient* client, UINT16 flags, UINT16 x,
UINT16 y);
@@ -244,6 +248,8 @@ extern "C"
pfnShadowClientCapabilities ClientCapabilities;
rdpShadowServer* server;
pfnShadowRelMouseEvent RelMouseEvent; /** @since version 3.15.0 */
};
/* Definition of message between subsystem and clients */

View File

@@ -248,7 +248,8 @@ static BOOL x11_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpSh
XFlush(x11->display);
XUnlockDisplay(x11->display);
}
#else
WLog_WARN(TAG, "KeyboardEvent not supported by backend, ignoring");
#endif
return TRUE;
}
@@ -336,6 +337,65 @@ static BOOL x11_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShado
XTestGrabControl(x11->display, False);
XFlush(x11->display);
XUnlockDisplay(x11->display);
#else
WLog_WARN(TAG, "MouseEvent not supported by backend, ignoring");
#endif
return TRUE;
}
static BOOL x11_shadow_input_rel_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
UINT16 flags, INT16 xDelta, INT16 yDelta)
{
#ifdef WITH_XTEST
x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
WINPR_ASSERT(x11);
unsigned int button = 0;
BOOL down = FALSE;
if (!subsystem || !client)
return FALSE;
rdpShadowServer* server = subsystem->server;
if (!server)
return FALSE;
rdpShadowSurface* surface = server->surface;
if (!surface)
return FALSE;
x11->lastMouseClient = client;
XLockDisplay(x11->display);
XTestGrabControl(x11->display, True);
if (flags & PTR_FLAGS_MOVE)
XTestFakeRelativeMotionEvent(x11->display, xDelta, yDelta, 0);
if (flags & PTR_FLAGS_BUTTON1)
button = 1;
else if (flags & PTR_FLAGS_BUTTON2)
button = 3;
else if (flags & PTR_FLAGS_BUTTON3)
button = 2;
else if (flags & PTR_XFLAGS_BUTTON1)
button = 4;
else if (flags & PTR_XFLAGS_BUTTON2)
button = 5;
if (flags & PTR_FLAGS_DOWN)
down = TRUE;
if (button)
XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
XTestGrabControl(x11->display, False);
XFlush(x11->display);
XUnlockDisplay(x11->display);
#else
WLog_WARN(TAG, "RelMouseEvent not supported by backend, ignoring");
#endif
return TRUE;
}
@@ -385,6 +445,8 @@ static BOOL x11_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
XTestGrabControl(x11->display, False);
XFlush(x11->display);
XUnlockDisplay(x11->display);
#else
WLog_WARN(TAG, "ExtendedMouseEvent not supported by backend, ignoring");
#endif
return TRUE;
}
@@ -1480,6 +1542,7 @@ static rdpShadowSubsystem* x11_shadow_subsystem_new(void)
subsystem->common.KeyboardEvent = x11_shadow_input_keyboard_event;
subsystem->common.UnicodeKeyboardEvent = x11_shadow_input_unicode_keyboard_event;
subsystem->common.MouseEvent = x11_shadow_input_mouse_event;
subsystem->common.RelMouseEvent = x11_shadow_input_rel_mouse_event;
subsystem->common.ExtendedMouseEvent = x11_shadow_input_extended_mouse_event;
subsystem->composite = FALSE;
subsystem->use_xshm = FALSE; /* temporarily disabled */

View File

@@ -52,6 +52,8 @@ int main(int argc, char** argv)
"Select or list monitors" },
{ "max-connections", COMMAND_LINE_VALUE_REQUIRED, "<number>", 0, NULL, -1, NULL,
"maximum connections allowed to server, 0 to deactivate" },
{ "mouse-relative", COMMAND_LINE_VALUE_BOOL, NULL, NULL, NULL, -1, NULL,
"enable support for relative mouse events" },
{ "rect", COMMAND_LINE_VALUE_REQUIRED, "<x,y,w,h>", NULL, NULL, -1, NULL,
"Select rectangle within monitor to share" },
{ "auth", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
@@ -140,7 +142,6 @@ int main(int argc, char** argv)
!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressiveV2, TRUE))
goto fail;
/* TODO: We do not implement relative mouse callbacks, so deactivate it for now */
if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, FALSE) ||
!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, FALSE))
goto fail;

View File

@@ -16,15 +16,24 @@
* limitations under the License.
*/
#include <winpr/assert.h>
#include <freerdp/config.h>
#include <freerdp/log.h>
#include "shadow.h"
#define TAG SERVER_TAG("shadow.input")
static BOOL shadow_input_synchronize_event(rdpInput* input, UINT32 flags)
{
WINPR_ASSERT(input);
rdpShadowClient* client = (rdpShadowClient*)input->context;
WINPR_ASSERT(client);
WINPR_ASSERT(client->server);
rdpShadowSubsystem* subsystem = client->server->subsystem;
WINPR_ASSERT(subsystem);
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16, client->mayInteract ? "use" : "discard", flags);
if (!client->mayInteract)
return TRUE;
@@ -33,9 +42,14 @@ static BOOL shadow_input_synchronize_event(rdpInput* input, UINT32 flags)
static BOOL shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
{
WINPR_ASSERT(input);
rdpShadowClient* client = (rdpShadowClient*)input->context;
WINPR_ASSERT(client);
WINPR_ASSERT(client->server);
rdpShadowSubsystem* subsystem = client->server->subsystem;
WINPR_ASSERT(subsystem);
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16, client->mayInteract ? "use" : "discard", flags);
if (!client->mayInteract)
return TRUE;
@@ -44,9 +58,14 @@ static BOOL shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 cod
static BOOL shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
{
WINPR_ASSERT(input);
rdpShadowClient* client = (rdpShadowClient*)input->context;
WINPR_ASSERT(client);
WINPR_ASSERT(client->server);
rdpShadowSubsystem* subsystem = client->server->subsystem;
WINPR_ASSERT(subsystem);
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16, client->mayInteract ? "use" : "discard", flags);
if (!client->mayInteract)
return TRUE;
@@ -55,8 +74,12 @@ static BOOL shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, U
static BOOL shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
{
WINPR_ASSERT(input);
rdpShadowClient* client = (rdpShadowClient*)input->context;
WINPR_ASSERT(client);
WINPR_ASSERT(client->server);
rdpShadowSubsystem* subsystem = client->server->subsystem;
WINPR_ASSERT(subsystem);
if (client->server->shareSubRect)
{
@@ -64,7 +87,7 @@ static BOOL shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UI
y += client->server->subRect.top;
}
if (!(flags & PTR_FLAGS_WHEEL))
if ((flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE)) == 0)
{
client->pointerX = x;
client->pointerY = y;
@@ -78,16 +101,47 @@ static BOOL shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UI
}
}
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16 ", x=%" PRIu16 ", y=%" PRIu16,
client->mayInteract ? "use" : "discard", flags, x, y);
if (!client->mayInteract)
return TRUE;
return IFCALLRESULT(TRUE, subsystem->MouseEvent, subsystem, client, flags, x, y);
}
static BOOL shadow_input_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
{
WINPR_ASSERT(input);
rdpShadowClient* client = (rdpShadowClient*)input->context;
WINPR_ASSERT(client);
WINPR_ASSERT(client->server);
rdpShadowSubsystem* subsystem = client->server->subsystem;
WINPR_ASSERT(subsystem);
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16 ", x=%" PRId16 ", y=%" PRId16,
client->mayInteract ? "use" : "discard", flags, xDelta, yDelta);
const uint16_t mask = PTR_FLAGS_MOVE | PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 |
PTR_FLAGS_BUTTON3 | PTR_XFLAGS_BUTTON1 | PTR_XFLAGS_BUTTON2;
if ((flags & mask) != 0)
{
WLog_WARN(TAG, "Unknown flags 0x%04" PRIx16, flags & ~mask);
}
if (!client->mayInteract)
return TRUE;
return IFCALLRESULT(TRUE, subsystem->RelMouseEvent, subsystem, client, flags, xDelta, yDelta);
}
static BOOL shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
{
WINPR_ASSERT(input);
rdpShadowClient* client = (rdpShadowClient*)input->context;
WINPR_ASSERT(client);
WINPR_ASSERT(client->server);
rdpShadowSubsystem* subsystem = client->server->subsystem;
WINPR_ASSERT(subsystem);
if (client->server->shareSubRect)
{
@@ -98,6 +152,8 @@ static BOOL shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UIN
client->pointerX = x;
client->pointerY = y;
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16 ", x=%" PRIu16 ", y=%" PRIu16,
client->mayInteract ? "use" : "discard", flags, x, y);
if (!client->mayInteract)
return TRUE;
@@ -106,9 +162,11 @@ static BOOL shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UIN
void shadow_input_register_callbacks(rdpInput* input)
{
WINPR_ASSERT(input);
input->SynchronizeEvent = shadow_input_synchronize_event;
input->KeyboardEvent = shadow_input_keyboard_event;
input->UnicodeKeyboardEvent = shadow_input_unicode_keyboard_event;
input->MouseEvent = shadow_input_mouse_event;
input->ExtendedMouseEvent = shadow_input_extended_mouse_event;
input->RelMouseEvent = shadow_input_rel_mouse_event;
}

View File

@@ -244,6 +244,13 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a
{
server->mayInteract = arg->Value ? TRUE : FALSE;
}
CommandLineSwitchCase(arg, "mouse-relative")
{
const BOOL val = arg->Value ? TRUE : FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, val) ||
!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, val))
return fail_at(arg, COMMAND_LINE_ERROR);
}
CommandLineSwitchCase(arg, "max-connections")
{
errno = 0;