diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index a3f5a6a25..96432b385 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -396,197 +396,57 @@ BOOL wlf_keyboard_modifiers(freerdp* instance, const UwacKeyboardModifiersEvent* BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev) { - int32_t x = 0, y = 0; - size_t i; - int touchId; + int32_t x, y; wlfContext* wlf; - if (!instance || !ev || !instance->context) - return FALSE; + WINPR_ASSERT(instance); + WINPR_ASSERT(ev); + wlf = instance->context; + WINPR_ASSERT(wlf); - wlf = (wlfContext*)instance->context; - touchId = ev->id; - - for (i = 0; i < MAX_CONTACTS; i++) - { - touchContact* contact = &wlf->contacts[i]; - if (contact->id == touchId) - { - contact->id = 0; - x = (int32_t)contact->pos_x; - y = (int32_t)contact->pos_y; - break; - } - } - - if (i == MAX_CONTACTS) - return FALSE; - - WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y); + x = ev->x; + y = ev->y; if (!scale_signed_coordinates(instance->context, &x, &y, TRUE)) return FALSE; -#if defined(CHANNEL_RDPEI_CLIENT) - RdpeiClientContext* rdpei = wlf->common.rdpei; - - if (wlf->contacts[i].emulate_mouse == TRUE) - { - UINT16 flags = 0; - flags |= PTR_FLAGS_BUTTON1; - - WINPR_ASSERT(x <= UINT16_MAX); - WINPR_ASSERT(y <= UINT16_MAX); - return freerdp_client_send_button_event(&wlf->common, FALSE, flags, x, y); - } - - if (!rdpei) - return FALSE; - { - int contactId; - - WINPR_ASSERT(rdpei->TouchEnd); - rdpei->TouchEnd(rdpei, touchId, x, y, &contactId); - } -#else - WLog_WARN(TAG, "Touch event detected but RDPEI support not compiled in. Recompile with " - "-DWITH_CHANNELS=ON"); -#endif - - return TRUE; + return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_UP, ev->id,0, x, y); } BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev) { int32_t x, y; - int i; - int touchId; wlfContext* wlf; - if (!instance || !ev || !instance->context) - return FALSE; - wlf = (wlfContext*)instance->context; + WINPR_ASSERT(instance); + WINPR_ASSERT(ev); + wlf = instance->context; + WINPR_ASSERT(wlf); + x = ev->x; y = ev->y; - touchId = ev->id; - - for (i = 0; i < MAX_CONTACTS; i++) - { - if (wlf->contacts[i].id == 0) - { - wlf->contacts[i].id = touchId; - wlf->contacts[i].pos_x = x; - wlf->contacts[i].pos_y = y; - wlf->contacts[i].emulate_mouse = FALSE; - break; - } - } - - if (i == MAX_CONTACTS) - return FALSE; - - WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y); if (!scale_signed_coordinates(instance->context, &x, &y, TRUE)) return FALSE; -#if defined(CHANNEL_RDPEI_CLIENT) - RdpeiClientContext* rdpei = wlf->common.rdpei; - - // Emulate mouse click if touch is not possible, like in login screen - if (!rdpei) - { - wlf->contacts[i].emulate_mouse = TRUE; - - UINT16 flags = 0; - flags |= PTR_FLAGS_DOWN; - flags |= PTR_FLAGS_MOVE; - flags |= PTR_FLAGS_BUTTON1; - - WINPR_ASSERT(x <= UINT16_MAX); - WINPR_ASSERT(y <= UINT16_MAX); - return freerdp_client_send_button_event(&wlf->common, FALSE, flags, x, y); - } - - WINPR_ASSERT(rdpei); - - { - int contactId; - - WINPR_ASSERT(rdpei->TouchBegin); - rdpei->TouchBegin(rdpei, touchId, x, y, &contactId); - } -#else - WLog_WARN(TAG, "Touch event detected but RDPEI support not compiled in. Recompile with " - "-DWITH_CHANNELS=ON"); -#endif - - return TRUE; + return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_DOWN, ev->id, 0,x, y); } BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev) { int32_t x, y; - int i; - int touchId; wlfContext* wlf; - if (!instance || !ev || !instance->context) - return FALSE; - wlf = (wlfContext*)instance->context; + WINPR_ASSERT(instance); + WINPR_ASSERT(ev); + wlf = instance->context; + WINPR_ASSERT(wlf); + x = ev->x; y = ev->y; - touchId = ev->id; - - for (i = 0; i < MAX_CONTACTS; i++) - { - if (wlf->contacts[i].id == touchId) - { - if ((fabs(wlf->contacts[i].pos_x - x) < DBL_EPSILON) && - (fabs(wlf->contacts[i].pos_y - y) < DBL_EPSILON)) - { - return TRUE; - } - wlf->contacts[i].pos_x = x; - wlf->contacts[i].pos_y = y; - break; - } - } - - if (i == MAX_CONTACTS) - return FALSE; - - WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y); if (!scale_signed_coordinates(instance->context, &x, &y, TRUE)) return FALSE; -#if defined(CHANNEL_RDPEI_CLIENT) - RdpeiClientContext* rdpei = ((wlfContext*)instance->context)->common.rdpei; - - if (wlf->contacts[i].emulate_mouse == TRUE) - { - UINT16 flags = 0; - flags |= PTR_FLAGS_MOVE; - - WINPR_ASSERT(x <= UINT16_MAX); - WINPR_ASSERT(y <= UINT16_MAX); - return freerdp_client_send_button_event(&wlf->common, FALSE, flags, x, y); - } - - if (!rdpei) - return FALSE; - - { - int contactId; - - WINPR_ASSERT(rdpei->TouchUpdate); - rdpei->TouchUpdate(rdpei, touchId, x, y, &contactId); - } -#else - WLog_WARN(TAG, "Touch event detected but RDPEI support not compiled in. Recompile with " - "-DWITH_CHANNELS=ON"); -#endif - - return TRUE; + return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_MOTION,0, ev->id, x, y); } diff --git a/client/Wayland/wlfreerdp.h b/client/Wayland/wlfreerdp.h index 5573f13ab..e1a465076 100644 --- a/client/Wayland/wlfreerdp.h +++ b/client/Wayland/wlfreerdp.h @@ -30,16 +30,6 @@ typedef struct wlf_clipboard wfClipboard; typedef struct s_wlfDispContext wlfDispContext; -#define MAX_CONTACTS 20 - -typedef struct -{ - int id; - double pos_x; - double pos_y; - BOOL emulate_mouse; -} touchContact; - typedef struct { rdpClientContext common; @@ -59,8 +49,6 @@ typedef struct wLog* log; CRITICAL_SECTION critical; wArrayList* events; - - touchContact contacts[MAX_CONTACTS]; } wlfContext; BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP); diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 1e051dc2b..56af7029b 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -189,7 +189,6 @@ int xf_input_init(xfContext* xfc, Window window) settings = xfc->common.context.settings; WINPR_ASSERT(settings); - memset(xfc->contacts, 0, sizeof(xfc->contacts)); xfc->firstDist = -1.0; xfc->z_vector = 0; xfc->px_vector = 0; @@ -596,7 +595,6 @@ static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtyp { int x, y; int touchId; - int contactId; RdpeiClientContext* rdpei = xfc->common.rdpei; if (!rdpei) @@ -611,16 +609,13 @@ static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtyp switch (evtype) { case XI_TouchBegin: - WLog_DBG(TAG, "TouchBegin: %d", touchId); - rdpei->TouchBegin(rdpei, touchId, x, y, &contactId); + freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_DOWN, touchId, x, y); break; case XI_TouchUpdate: - WLog_DBG(TAG, "TouchUpdate: %d", touchId); - rdpei->TouchUpdate(rdpei, touchId, x, y, &contactId); + freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_MOTION, touchId, x, y); break; case XI_TouchEnd: - WLog_DBG(TAG, "TouchEnd: %d", touchId); - rdpei->TouchEnd(rdpei, touchId, x, y, &contactId); + freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_UP, touchId, x, y); break; default: break; diff --git a/client/common/client.c b/client/common/client.c index 7ad69c06f..2ed6201bd 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -21,6 +21,8 @@ #include #include +#include +#include #include @@ -1358,6 +1360,192 @@ BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL rela return TRUE; } + +static BOOL freerdp_handle_touch_up(rdpClientContext* cctx, const FreeRDP_TouchContact* contact) +{ + WINPR_ASSERT(cctx); + WINPR_ASSERT(contact); + +#if defined(CHANNEL_RDPEI_CLIENT) + RdpeiClientContext* rdpei = cctx->rdpei; + + if (!rdpei) + { + UINT16 flags = 0; + flags |= PTR_FLAGS_BUTTON1; + + WINPR_ASSERT(contact->x <= UINT16_MAX); + WINPR_ASSERT(contact->y <= UINT16_MAX); + return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y); + } + else + { + int contactId; + + if (rdpei->TouchRawEvent) + { + const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP; + const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0) + ? CONTACT_DATA_PRESSURE_PRESENT + : 0; + rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags, + contactFlags, contact->pressure); + } + else + { + WINPR_ASSERT(rdpei->TouchEnd); + rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId); + } + } +#else + WLog_WARN(TAG, "Touch event detected but RDPEI support not compiled in. Recompile with " + "-DWITH_CHANNELS=ON"); +#endif + + return TRUE; +} + +static BOOL freerdp_handle_touch_down(rdpClientContext* cctx, const FreeRDP_TouchContact* contact) +{ + WINPR_ASSERT(cctx); + WINPR_ASSERT(contact); + +#if defined(CHANNEL_RDPEI_CLIENT) + RdpeiClientContext* rdpei = cctx->rdpei; + + // Emulate mouse click if touch is not possible, like in login screen + if (!rdpei) + { + UINT16 flags = 0; + flags |= PTR_FLAGS_DOWN; + flags |= PTR_FLAGS_MOVE; + flags |= PTR_FLAGS_BUTTON1; + + WINPR_ASSERT(contact->x <= UINT16_MAX); + WINPR_ASSERT(contact->y <= UINT16_MAX); + return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y); + } + else + { + int contactId; + + if (rdpei->TouchRawEvent) + { + const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN; + const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0) + ? CONTACT_DATA_PRESSURE_PRESENT + : 0; + rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags, + contactFlags, contact->pressure); + } + else + { + WINPR_ASSERT(rdpei->TouchBegin); + rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId); + } + } +#else + WLog_WARN(TAG, "Touch event detected but RDPEI support not compiled in. Recompile with " + "-DWITH_CHANNELS=ON"); +#endif + + return TRUE; +} + +static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx, const FreeRDP_TouchContact* contact) +{ + WINPR_ASSERT(cctx); + WINPR_ASSERT(contact); + +#if defined(CHANNEL_RDPEI_CLIENT) + RdpeiClientContext* rdpei = cctx->rdpei; + + if (!rdpei) + { + UINT16 flags = 0; + flags |= PTR_FLAGS_MOVE; + + WINPR_ASSERT(contact->x <= UINT16_MAX); + WINPR_ASSERT(contact->y <= UINT16_MAX); + return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y); + } + else + { + int contactId; + + if (rdpei->TouchRawEvent) + { + const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE; + const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0) + ? CONTACT_DATA_PRESSURE_PRESENT + : 0; + rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags, + contactFlags, contact->pressure); + } + else + { + WINPR_ASSERT(rdpei->TouchUpdate); + rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId); + } + } +#else + WLog_WARN(TAG, "Touch event detected but RDPEI support not compiled in. Recompile with " + "-DWITH_CHANNELS=ON"); +#endif + + return TRUE; +} + +static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId, + UINT32 pressure, INT32 x, INT32 y, + const FreeRDP_TouchContact** ppcontact) +{ + WINPR_ASSERT(cctx); + WINPR_ASSERT(ppcontact); + + for (size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++) + { + FreeRDP_TouchContact* contact = &cctx->contacts[i]; + + if (contact->id == touchId) + { + *ppcontact = contact; + + contact->flags = flags; + contact->pressure = pressure; + contact->x = x; + contact->y = y; + return TRUE; + } + } + + return FALSE; +} + +BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger, + UINT32 pressure, INT32 x, INT32 y) +{ + WINPR_ASSERT(cctx); + + const FreeRDP_TouchContact* contact = NULL; + + if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact)) + return FALSE; + + switch (flags) + { + case FREERDP_TOUCH_DOWN: + return freerdp_handle_touch_down(cctx, contact); + case FREERDP_TOUCH_UP: + return freerdp_handle_touch_up(cctx, contact); + case FREERDP_TOUCH_MOTION: + return freerdp_handle_touch_motion(cctx, contact); + default: + WLog_WARN(TAG, "Unhandled FreeRDPTouchEventType %d, ignoring", flags); + return FALSE; + } +} + BOOL freerdp_client_load_channels(freerdp* instance) { WINPR_ASSERT(instance); diff --git a/include/freerdp/client.h b/include/freerdp/client.h index d8c06d708..15172e409 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -79,6 +79,17 @@ extern "C" typedef int (*pRdpClientEntry)(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); /* Common Client Interface */ +#define FREERDP_MAX_TOUCH_CONTACTS 10 + + typedef struct + { + ALIGN64 INT32 id; + ALIGN64 UINT32 count; + ALIGN64 INT32 x; + ALIGN64 INT32 y; + ALIGN64 UINT32 flags; + ALIGN64 UINT32 pressure; + } FreeRDP_TouchContact; struct rdp_client_context { @@ -106,7 +117,8 @@ extern "C" #else UINT64 reserved3[2]; #endif - UINT64 reserved[128 - 8]; /**< (offset 8) */ + ALIGN64 FreeRDP_TouchContact contacts[FREERDP_MAX_TOUCH_CONTACTS]; /**< (offset 8) */ + UINT64 reserved[128 - 68]; /**< (offset 68) */ }; /* Common client functions */ @@ -193,6 +205,17 @@ extern "C" FREERDP_API BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance)); + typedef enum + { + FREERDP_TOUCH_DOWN = 0x01, + FREERDP_TOUCH_UP = 0x02, + FREERDP_TOUCH_MOTION = 0x04, + FREERDP_TOUCH_HAS_PRESSURE = 0x100 + } FreeRDPTouchEventType; + + FREERDP_API BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger, + UINT32 pressure, INT32 x, INT32 y); + FREERDP_API BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags); FREERDP_API BOOL freerdp_client_send_mouse_event(rdpClientContext* cctx, UINT64 mflags, INT32 x,