From b385e61bc0a05d1ca0af204edc6430a679ee9418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 13 May 2013 19:17:25 -0400 Subject: [PATCH] xfreerdp-client: start trying to send multitouch events --- channels/rdpei/client/CMakeLists.txt | 5 ++ channels/rdpei/client/rdpei_main.c | 94 +++++++++++++++++++++++----- channels/rdpei/client/rdpei_main.h | 35 ----------- client/X11/CMakeLists.txt | 2 + client/X11/xf_channels.c | 46 ++++++++++++++ client/X11/xf_channels.h | 30 +++++++++ client/X11/xf_input.c | 60 +++++++++++++----- client/X11/xf_interface.c | 12 +--- client/X11/xfreerdp.h | 4 ++ include/freerdp/client/rdpei.h | 41 ++++++++++++ 10 files changed, 252 insertions(+), 77 deletions(-) create mode 100644 client/X11/xf_channels.c create mode 100644 client/X11/xf_channels.h diff --git a/channels/rdpei/client/CMakeLists.txt b/channels/rdpei/client/CMakeLists.txt index b3aacdcb2..b96082550 100644 --- a/channels/rdpei/client/CMakeLists.txt +++ b/channels/rdpei/client/CMakeLists.txt @@ -33,6 +33,11 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp MODULES freerdp-common freerdp-utils) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-sysinfo) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index a624d83e0..026f73c93 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -35,14 +36,7 @@ #include "rdpei_main.h" -struct _RDPEI_LISTENER_CALLBACK -{ - IWTSListenerCallback iface; - - IWTSPlugin* plugin; - IWTSVirtualChannelManager* channel_mgr; -}; -typedef struct _RDPEI_LISTENER_CALLBACK RDPEI_LISTENER_CALLBACK; +#define MAX_CONTACTS 512 struct _RDPEI_CHANNEL_CALLBACK { @@ -54,12 +48,28 @@ struct _RDPEI_CHANNEL_CALLBACK }; typedef struct _RDPEI_CHANNEL_CALLBACK RDPEI_CHANNEL_CALLBACK; +struct _RDPEI_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + RDPEI_CHANNEL_CALLBACK* channel_callback; +}; +typedef struct _RDPEI_LISTENER_CALLBACK RDPEI_LISTENER_CALLBACK; + struct _RDPEI_PLUGIN { IWTSPlugin iface; IWTSListener* listener; RDPEI_LISTENER_CALLBACK* listener_callback; + + int version; + UINT64 currentFrameTime; + UINT64 previousFrameTime; + RDPINPUT_TOUCH_FRAME frame; + RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS]; }; typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN; @@ -164,29 +174,24 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) return 0; } -int rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback) +int rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback, RDPINPUT_TOUCH_FRAME* frame) { int status; wStream* s; UINT32 pduLength; UINT32 encodeTime; UINT16 frameCount; - RDPINPUT_TOUCH_FRAME frame; - RDPINPUT_CONTACT_DATA contact; - encodeTime = 123; + encodeTime = 0; frameCount = 1; - frame.contactCount = 1; - frame.contacts = &contact; - s = Stream_New(NULL, 512); Stream_Seek(s, RDPINPUT_HEADER_LENGTH); rdpei_write_4byte_unsigned(s, encodeTime); rdpei_write_2byte_unsigned(s, frameCount); - rdpei_write_touch_frame(s, &frame); + rdpei_write_touch_frame(s, frame); Stream_SealLength(s); pduLength = Stream_Length(s); @@ -298,6 +303,7 @@ static int rdpei_on_new_channel_connection(IWTSListenerCallback* pListenerCallba callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; + listener_callback->channel_callback = callback; *ppCallback = (IWTSVirtualChannelCallback*) callback; @@ -343,7 +349,53 @@ static int rdpei_plugin_terminated(IWTSPlugin* pPlugin) int rdpei_get_version(RdpeiClientContext* context) { - //RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + return rdpei->version; +} + +int rdpei_begin_frame(RdpeiClientContext* context) +{ + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + + rdpei->frame.contactCount = 0; + rdpei->frame.frameOffset = 0; + + return 1; +} + +int rdpei_end_frame(RdpeiClientContext* context) +{ + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_CHANNEL_CALLBACK* callback = rdpei->listener_callback->channel_callback; + + if (!rdpei->previousFrameTime && !rdpei->currentFrameTime) + { + rdpei->currentFrameTime = (UINT64) GetTickCount64(); + rdpei->frame.frameOffset = 0; + } + else + { + rdpei->currentFrameTime = (UINT64) GetTickCount64(); + rdpei->frame.frameOffset = rdpei->currentFrameTime - rdpei->previousFrameTime; + } + + rdpei_send_touch_event_pdu(callback, &rdpei->frame); + rdpei->previousFrameTime = rdpei->currentFrameTime; + rdpei->frame.contactCount = 0; + + return 1; +} + +int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact) +{ + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + + if (rdpei->frame.contactCount < MAX_CONTACTS) + { + CopyMemory(&(rdpei->contacts[rdpei->frame.contactCount]), contact, sizeof(RDPINPUT_CONTACT_DATA)); + rdpei->frame.contactCount++; + } + return 1; } @@ -369,10 +421,18 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) rdpei->iface.Disconnected = NULL; rdpei->iface.Terminated = rdpei_plugin_terminated; + rdpei->version = 1; + rdpei->currentFrameTime = 0; + rdpei->previousFrameTime = 0; + rdpei->frame.contacts = (RDPINPUT_CONTACT_DATA*) rdpei->contacts; + context = (RdpeiClientContext*) malloc(sizeof(RdpeiClientContext)); context->handle = (void*) rdpei; context->GetVersion = rdpei_get_version; + context->BeginFrame = rdpei_begin_frame; + context->EndFrame = rdpei_end_frame; + context->AddContact = rdpei_add_contact; rdpei->iface.pInterface = (void*) context; diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index 6438762f5..5781ee654 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -33,41 +33,6 @@ #define RDPINPUT_HEADER_LENGTH 6 -#define CONTACT_DATA_CONTACTRECT_PRESENT 0x0001 -#define CONTACT_DATA_ORIENTATION_PRESENT 0x0002 -#define CONTACT_DATA_PRESSURE_PRESENT 0x0004 - -#define CONTACT_FLAG_DOWN 0x0001 -#define CONTACT_FLAG_UPDATE 0x0002 -#define CONTACT_FLAG_UP 0x0004 -#define CONTACT_FLAG_INRANGE 0x0008 -#define CONTACT_FLAG_INCONTACT 0x0010 -#define CONTACT_FLAG_CANCELED 0x0020 - -struct _RDPINPUT_CONTACT_DATA -{ - UINT32 contactId; - UINT32 fieldsPresent; - INT32 x; - INT32 y; - UINT32 contactFlags; - INT32 contactRectLeft; - INT32 contactRectTop; - INT32 contactRectRight; - INT32 contactRectBottom; - UINT32 orientation; - UINT32 pressure; -}; -typedef struct _RDPINPUT_CONTACT_DATA RDPINPUT_CONTACT_DATA; - -struct _RDPINPUT_TOUCH_FRAME -{ - UINT32 contactCount; - UINT64 frameOffset; - RDPINPUT_CONTACT_DATA* contacts; -}; -typedef struct _RDPINPUT_TOUCH_FRAME RDPINPUT_TOUCH_FRAME; - /* Protocol Version */ #define RDPINPUT_PROTOCOL_V1 0x00010000 diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 7ccad8f37..f1d8ba08f 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -32,6 +32,8 @@ set(${MODULE_PREFIX}_SRCS xf_event.h xf_input.c xf_input.h + xf_channels.c + xf_channels.h xf_cliprdr.c xf_cliprdr.h xf_monitor.c diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c new file mode 100644 index 000000000..5b95a2db9 --- /dev/null +++ b/client/X11/xf_channels.c @@ -0,0 +1,46 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Client Channels + * + * Copyright 2013 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf_channels.h" + +#include "xf_interface.h" +#include "xfreerdp.h" + +int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface) +{ + xfInfo* xfi = ((xfContext*) instance->context)->xfi; + + printf("OnChannelConnected: %s\n", name); + + if (strcmp(name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + xfi->rdpei = (RdpeiClientContext*) pInterface; + } + + return 0; +} + +int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface) +{ + return 0; +} diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h new file mode 100644 index 000000000..1aeaf1a66 --- /dev/null +++ b/client/X11/xf_channels.h @@ -0,0 +1,30 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Client Channels + * + * Copyright 2013 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __XF_CHANNELS_H +#define __XF_CHANNELS_H + +#include +#include +#include + +int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface); +int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface); + +#endif diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 27214855b..e0e6eafe0 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -94,13 +94,13 @@ int xf_input_init(xfInfo* xfi, Window window) for (j = 0; j < dev->num_classes; j++) { XIAnyClassInfo* class = dev->classes[j]; - //XITouchClassInfo* t = (XITouchClassInfo*) class; + XITouchClassInfo* t = (XITouchClassInfo*) class; if (class->type != XITouchClass) continue; - //printf("%s %s touch device, supporting %d touches.\n", - // dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", t->num_touches); + printf("%s %s touch device, supporting %d touches.\n", + dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", t->num_touches); } } @@ -257,7 +257,7 @@ void xf_input_touch_end(xfInfo* xfi, XIDeviceEvent* event) //contacts[i].pos_y = (int)event->event_y; active_contacts--; - break; + break;printf("TouchBegin\n"); } } } @@ -301,18 +301,50 @@ int xf_input_handle_event_local(xfInfo* xfi, XEvent* event) return 0; } -int xf_input_touch_begin_remote(xfInfo* xfi, XIDeviceEvent* event) +char* xf_input_touch_state_string(DWORD flags) { - return 0; + if (flags & CONTACT_FLAG_DOWN) + return "TouchBegin"; + else if (flags & CONTACT_FLAG_UPDATE) + return "TouchUpdate"; + else if (flags & CONTACT_FLAG_UP) + return "TouchEnd"; + else + return "TouchUnknown"; } -int xf_input_touch_update_remote(xfInfo* xfi, XIDeviceEvent* event) +int xf_input_touch_remote(xfInfo* xfi, XIDeviceEvent* event, DWORD flags) { - return 0; -} + int x, y; + int touchId; + RDPINPUT_CONTACT_DATA contact; + RdpeiClientContext* rdpei = xfi->rdpei; + + if (!rdpei) + return 0; + + touchId = event->detail; + x = (int) event->event_x; + y = (int) event->event_y; + ZeroMemory(&contact, sizeof(RDPINPUT_CONTACT_DATA)); + + if ((x < 0) || (y < 0)) + return 0; + + printf("%s: id: %d x: %d y: %d\n", + xf_input_touch_state_string(flags), + touchId, x, y); + + contact.contactId = touchId % 0xFF; + contact.fieldsPresent = 0; + contact.x = x; + contact.y = y; + contact.contactFlags = flags; + + rdpei->BeginFrame(rdpei); + rdpei->AddContact(rdpei, &contact); + rdpei->EndFrame(rdpei); -int xf_input_touch_end_remote(xfInfo* xfi, XIDeviceEvent* event) -{ return 0; } @@ -327,15 +359,15 @@ int xf_input_handle_event_remote(xfInfo* xfi, XEvent* event) switch (cookie->evtype) { case XI_TouchBegin: - xf_input_touch_begin_remote(xfi, cookie->data); + xf_input_touch_remote(xfi, cookie->data, CONTACT_FLAG_DOWN); break; case XI_TouchUpdate: - xf_input_touch_update_remote(xfi, cookie->data); + xf_input_touch_remote(xfi, cookie->data, CONTACT_FLAG_UPDATE); break; case XI_TouchEnd: - xf_input_touch_end_remote(xfi, cookie->data); + xf_input_touch_remote(xfi, cookie->data, CONTACT_FLAG_UP); break; default: diff --git a/client/X11/xf_interface.c b/client/X11/xf_interface.c index 6eee091bf..fb1dd9699 100644 --- a/client/X11/xf_interface.c +++ b/client/X11/xf_interface.c @@ -83,6 +83,7 @@ #include "xf_monitor.h" #include "xf_graphics.h" #include "xf_keyboard.h" +#include "xf_channels.h" #include "xfreerdp.h" @@ -653,17 +654,6 @@ int _xf_error_handler(Display* d, XErrorEvent* ev) return xf_error_handler(d, ev); } -int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface) -{ - //printf("OnChannelConnected: %s\n", name); - return 0; -} - -int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface) -{ - return 0; -} - /** * Callback given to freerdp_connect() to process the pre-connect operations. * It will fill the rdp_freerdp structure (instance) with the appropriate options to use for the connection. diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 916ca0425..3b530a529 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -22,6 +22,7 @@ #include "xf_window.h" #include "xf_monitor.h" +#include "xf_channels.h" struct xf_WorkArea { @@ -162,6 +163,9 @@ struct xf_info Atom WM_STATE; Atom WM_PROTOCOLS; Atom WM_DELETE_WINDOW; + + /* Channels */ + RdpeiClientContext* rdpei; }; void xf_create_window(xfInfo* xfi); diff --git a/include/freerdp/client/rdpei.h b/include/freerdp/client/rdpei.h index 3ebf41c8a..0a41ac423 100644 --- a/include/freerdp/client/rdpei.h +++ b/include/freerdp/client/rdpei.h @@ -20,6 +20,41 @@ #ifndef FREERDP_CHANNEL_CLIENT_RDPEI_H #define FREERDP_CHANNEL_CLIENT_RDPEI_H +#define CONTACT_DATA_CONTACTRECT_PRESENT 0x0001 +#define CONTACT_DATA_ORIENTATION_PRESENT 0x0002 +#define CONTACT_DATA_PRESSURE_PRESENT 0x0004 + +#define CONTACT_FLAG_DOWN 0x0001 +#define CONTACT_FLAG_UPDATE 0x0002 +#define CONTACT_FLAG_UP 0x0004 +#define CONTACT_FLAG_INRANGE 0x0008 +#define CONTACT_FLAG_INCONTACT 0x0010 +#define CONTACT_FLAG_CANCELED 0x0020 + +struct _RDPINPUT_CONTACT_DATA +{ + UINT32 contactId; + UINT32 fieldsPresent; + INT32 x; + INT32 y; + UINT32 contactFlags; + INT32 contactRectLeft; + INT32 contactRectTop; + INT32 contactRectRight; + INT32 contactRectBottom; + UINT32 orientation; + UINT32 pressure; +}; +typedef struct _RDPINPUT_CONTACT_DATA RDPINPUT_CONTACT_DATA; + +struct _RDPINPUT_TOUCH_FRAME +{ + UINT32 contactCount; + UINT64 frameOffset; + RDPINPUT_CONTACT_DATA* contacts; +}; +typedef struct _RDPINPUT_TOUCH_FRAME RDPINPUT_TOUCH_FRAME; + /** * Client Interface */ @@ -29,6 +64,9 @@ typedef struct _rdpei_client_context RdpeiClientContext; typedef int (*pcRdpeiGetVersion)(RdpeiClientContext* context); +typedef int (*pcRdpeiBeginFrame)(RdpeiClientContext* context); +typedef int (*pcRdpeiEndFrame)(RdpeiClientContext* context); +typedef int (*pcRdpeiAddContact)(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact); struct _rdpei_client_context { @@ -36,6 +74,9 @@ struct _rdpei_client_context void* custom; pcRdpeiGetVersion GetVersion; + pcRdpeiBeginFrame BeginFrame; + pcRdpeiEndFrame EndFrame; + pcRdpeiAddContact AddContact; }; #endif /* FREERDP_CHANNEL_CLIENT_RDPEI_H */