From 7073e7e96467cd1c6816f41cbc2b6fac71b783f9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 2 Mar 2021 09:34:39 +0100 Subject: [PATCH] Proper pointer event handling for wayland (cherry picked from commit 8732ff68abbaa0c65928d7c3236bd496da334c9b) --- client/Wayland/wlf_input.c | 128 +++++++++++++++++++++++++++++++++---- client/Wayland/wlf_input.h | 3 + client/Wayland/wlfreerdp.c | 64 ++++++++++++++----- client/Wayland/wlfreerdp.h | 1 + 4 files changed, 168 insertions(+), 28 deletions(-) diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index 22041eaa2588..735245b3bd8c 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -134,26 +134,44 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* } BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev) +{ + wlfContext* context; + if (!instance || !instance->context || !ev) + return FALSE; + + context = (wlfContext*)instance->context; + ArrayList_Add(context->events, ev); + return TRUE; +} + +BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev) +{ + wlfContext* context; + if (!instance || !instance->context || !ev) + return FALSE; + + context = (wlfContext*)instance->context; + ArrayList_Add(context->events, ev); + return TRUE; +} + +static BOOL wlf_handle_wheel(freerdp* instance, uint32_t x, uint32_t y, uint32_t axis, + int32_t value) { rdpInput* input; UINT16 flags = 0; int32_t direction; - uint32_t x, y; - uint32_t i; + uint32_t avalue = abs(value); - if (!instance || !ev || !instance->input) - return FALSE; - - x = ev->x; - y = ev->y; + input = instance->input; if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) return FALSE; input = instance->input; - direction = ev->value; - switch (ev->axis) + direction = value; + switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: flags |= PTR_FLAGS_WHEEL; @@ -176,16 +194,102 @@ BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev) * positive: 0 ... 0xFF -> slow ... fast * negative: 0 ... 0xFF -> fast ... slow */ - for (i = 0; i < abs(direction); i++) + + while (avalue > 0) { - uint32_t cflags = flags | 0x78; + const uint32_t cval = avalue > 0xFF ? 0xFF : avalue; + uint32_t cflags = flags | cval; /* Convert negative values to 9bit twos complement */ if (flags & PTR_FLAGS_WHEEL_NEGATIVE) - cflags = (flags & 0xFF00) | (0x100 - (cflags & 0xFF)); + cflags = (flags & 0xFF00) | (0x100 - cval); if (!freerdp_input_send_mouse_event(input, cflags, (UINT16)x, (UINT16)y)) return FALSE; + + avalue -= cval; } + return TRUE; +} +BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev) +{ + BOOL success = TRUE; + BOOL handle = FALSE; + size_t x; + wlfContext* context; + enum wl_pointer_axis_source source; + + if (!instance || !ev || !instance->input || !instance->context) + return FALSE; + + context = (wlfContext*)instance->context; + + for (x = 0; x < ArrayList_Count(context->events); x++) + { + UwacEvent* ev = ArrayList_GetItem(context->events, x); + if (!ev) + continue; + if (ev->type == UWAC_EVENT_POINTER_SOURCE) + { + handle = TRUE; + source = ev->mouse_source.axis_source; + } + } + + /* We need source events to determine how to interpret the data */ + if (handle) + { + for (x = 0; x < ArrayList_Count(context->events); x++) + { + UwacEvent* ev = ArrayList_GetItem(context->events, x); + if (!ev) + continue; + + switch (source) + { + /* If we have a mouse wheel, just use discrete data */ + case WL_POINTER_AXIS_SOURCE_WHEEL: +#if defined(WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION) + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: +#endif + if (ev->type == UWAC_EVENT_POINTER_AXIS_DISCRETE) + { + /* Get the number of steps, multiply by default step width of 120 */ + int32_t val = ev->mouse_axis.value * 0x78; + /* No wheel event received, success! */ + if (!wlf_handle_wheel(instance, ev->mouse_axis.x, ev->mouse_axis.y, + ev->mouse_axis.axis, val)) + success = FALSE; + } + break; + /* If we have a touch pad we get actual data, scale */ + case WL_POINTER_AXIS_SOURCE_FINGER: + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: + if (ev->type == UWAC_EVENT_POINTER_AXIS) + { + double dval = wl_fixed_to_double(ev->mouse_axis.value); + int32_t val = dval * 0x78 / 10.0; + if (!wlf_handle_wheel(instance, ev->mouse_axis.x, ev->mouse_axis.y, + ev->mouse_axis.axis, val)) + success = FALSE; + } + break; + default: + break; + } + } + } + ArrayList_Clear(context->events); + return success; +} + +BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev) +{ + wlfContext* context; + if (!instance || !instance->context || !ev) + return FALSE; + + context = (wlfContext*)instance->context; + ArrayList_Add(context->events, ev); return TRUE; } diff --git a/client/Wayland/wlf_input.h b/client/Wayland/wlf_input.h index 2382dd8b84b9..ff41300c5ec0 100644 --- a/client/Wayland/wlf_input.h +++ b/client/Wayland/wlf_input.h @@ -30,6 +30,9 @@ BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEven BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev); BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev); BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev); +BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev); +BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev); +BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev); BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev); BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev); BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev); diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index c7a9fca59b6e..65e29bc51109 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -362,12 +362,22 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) break; case UWAC_EVENT_POINTER_AXIS: + if (!wlf_handle_pointer_axis(instance, &event.mouse_axis)) + return FALSE; break; case UWAC_EVENT_POINTER_AXIS_DISCRETE: - if (!wlf_handle_pointer_axis(instance, &event.mouse_axis)) + if (!wlf_handle_pointer_axis_discrete(instance, &event.mouse_axis)) return FALSE; + break; + case UWAC_EVENT_POINTER_FRAME: + if (!wlf_handle_pointer_frame(instance, &event.mouse_frame)) + return FALSE; + break; + case UWAC_EVENT_POINTER_SOURCE: + if (!wlf_handle_pointer_source(instance, &event.mouse_source)) + return FALSE; break; case UWAC_EVENT_KEY: @@ -561,8 +571,37 @@ static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) return 1; } +static void wlf_client_free(freerdp* instance, rdpContext* context) +{ + wlfContext* wlf = (wlfContext*)instance->context; + + if (!context) + return; + + if (wlf->display) + UwacCloseDisplay(&wlf->display); + + if (wlf->displayHandle) + CloseHandle(wlf->displayHandle); + ArrayList_Free(wlf->events); + DeleteCriticalSection(&wlf->critical); +} + +static void* uwac_event_clone(const void* val) +{ + UwacEvent* copy; + UwacEvent* ev = (UwacEvent*)val; + + copy = calloc(1, sizeof(UwacEvent)); + if (!copy) + return NULL; + *copy = *ev; + return copy; +} + static BOOL wlf_client_new(freerdp* instance, rdpContext* context) { + wObject* obj; UwacReturnCode status; wlfContext* wfl = (wlfContext*)context; @@ -590,24 +629,17 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context) if (!wfl->displayHandle) return FALSE; - InitializeCriticalSection(&wfl->critical); - - return TRUE; -} - -static void wlf_client_free(freerdp* instance, rdpContext* context) -{ - wlfContext* wlf = (wlfContext*)instance->context; + wfl->events = ArrayList_New(FALSE); + if (!wfl->events) + return FALSE; - if (!context) - return; + obj = ArrayList_Object(wfl->events); + obj->fnObjectNew = uwac_event_clone; + obj->fnObjectFree = free; - if (wlf->display) - UwacCloseDisplay(&wlf->display); + InitializeCriticalSection(&wfl->critical); - if (wlf->displayHandle) - CloseHandle(wlf->displayHandle); - DeleteCriticalSection(&wlf->critical); + return TRUE; } static int wfl_client_start(rdpContext* context) diff --git a/client/Wayland/wlfreerdp.h b/client/Wayland/wlfreerdp.h index d84f91cbba2a..6af13bbbc055 100644 --- a/client/Wayland/wlfreerdp.h +++ b/client/Wayland/wlfreerdp.h @@ -53,6 +53,7 @@ struct wlf_context wlfDispContext* disp; wLog* log; CRITICAL_SECTION critical; + wArrayList* events; }; BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP);