diff --git a/channels/rdpei/CMakeLists.txt b/channels/rdpei/CMakeLists.txt index e5ffe6afc..a93af67c5 100644 --- a/channels/rdpei/CMakeLists.txt +++ b/channels/rdpei/CMakeLists.txt @@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() \ No newline at end of file diff --git a/channels/rdpei/client/CMakeLists.txt b/channels/rdpei/client/CMakeLists.txt index db3794621..875efac86 100644 --- a/channels/rdpei/client/CMakeLists.txt +++ b/channels/rdpei/client/CMakeLists.txt @@ -20,11 +20,10 @@ define_channel_client("rdpei") set(${MODULE_PREFIX}_SRCS rdpei_main.c rdpei_main.h - rdpei_common.c - rdpei_common.h) + ../rdpei_common.c + ../rdpei_common.h) include_directories(..) - add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index 4da19ee84..bc7c63da3 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -29,31 +29,11 @@ #include #include +#include #include #define TAG CHANNELS_TAG("rdpei.client") -#define RDPINPUT_HEADER_LENGTH 6 - -/* Protocol Version */ - -#define RDPINPUT_PROTOCOL_V10 0x00010000 -#define RDPINPUT_PROTOCOL_V101 0x00010001 - -/* Client Ready Flags */ - -#define READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001 -#define READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002 - -/* Input Event Ids */ - -#define EVENTID_SC_READY 0x0001 -#define EVENTID_CS_READY 0x0002 -#define EVENTID_TOUCH 0x0003 -#define EVENTID_SUSPEND_TOUCH 0x0004 -#define EVENTID_RESUME_TOUCH 0x0005 -#define EVENTID_DISMISS_HOVERING_CONTACT 0x0006 - #define RDPINPUT_CONTACT_STATE_INITIAL 0x0000 #define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001 #define RDPINPUT_CONTACT_STATE_HOVERING 0x0002 diff --git a/channels/rdpei/client/rdpei_common.c b/channels/rdpei/rdpei_common.c similarity index 96% rename from channels/rdpei/client/rdpei_common.c rename to channels/rdpei/rdpei_common.c index 3f6b3d819..62625eccc 100644 --- a/channels/rdpei/client/rdpei_common.c +++ b/channels/rdpei/rdpei_common.c @@ -3,6 +3,7 @@ * Input Virtual Channel Extension * * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -587,3 +588,23 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) return TRUE; } + +void touch_event_reset(RDPINPUT_TOUCH_EVENT *event) +{ + int i; + + for (i = 0; i < event->frameCount; i++) + touch_frame_reset(&event->frames[i]); + + free(event->frames); + event->frames = NULL; + event->frameCount = 0; +} + + +void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame) +{ + free(frame->contacts); + frame->contacts = NULL; + frame->contactCount = 0; +} diff --git a/channels/rdpei/client/rdpei_common.h b/channels/rdpei/rdpei_common.h similarity index 70% rename from channels/rdpei/client/rdpei_common.h rename to channels/rdpei/rdpei_common.h index 293919f67..34d1edd64 100644 --- a/channels/rdpei/client/rdpei_common.h +++ b/channels/rdpei/rdpei_common.h @@ -3,6 +3,7 @@ * Input Virtual Channel Extension * * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +18,22 @@ * limitations under the License. */ -#ifndef FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H -#define FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H +#ifndef FREERDP_CHANNEL_RDPEI_COMMON_H +#define FREERDP_CHANNEL_RDPEI_COMMON_H #include #include +#include + +/** @brief input event ids */ +enum { + EVENTID_SC_READY = 0x0001, + EVENTID_CS_READY = 0x0002, + EVENTID_TOUCH = 0x0003, + EVENTID_SUSPEND_TOUCH = 0x0004, + EVENTID_RESUME_TOUCH = 0x0005, + EVENTID_DISMISS_HOVERING_CONTACT = 0x0006 +}; BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value); BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value); @@ -34,5 +46,8 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value); BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value); BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value); -#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H */ +void touch_event_reset(RDPINPUT_TOUCH_EVENT *event); +void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame); + +#endif /* FREERDP_CHANNEL_RDPEI_COMMON_H */ diff --git a/channels/rdpei/server/CMakeLists.txt b/channels/rdpei/server/CMakeLists.txt new file mode 100644 index 000000000..e98c4576f --- /dev/null +++ b/channels/rdpei/server/CMakeLists.txt @@ -0,0 +1,38 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2014 Thincast Technologies Gmbh. +# Copyright 2014 David FORT +# +# 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. + +define_channel_server("rdpei") + +set(${MODULE_PREFIX}_SRCS + rdpei_main.c + rdpei_main.h + ../rdpei_common.c + ../rdpei_common.h +) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c new file mode 100644 index 000000000..95f70f567 --- /dev/null +++ b/channels/rdpei/server/rdpei_main.c @@ -0,0 +1,460 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel server-side implementation + * + * Copyright 2014 Thincast Technologies Gmbh. + * Copyright 2014 David FORT + * + * 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 +#include +#include + +#include "rdpei_main.h" +#include "../rdpei_common.h" +#include +#include + +/** @brief */ +enum RdpEiState { + STATE_INITIAL, + STATE_WAITING_CLIENT_READY, + STATE_WAITING_FRAME, + STATE_SUSPENDED, +}; + +struct _rdpei_server_private +{ + HANDLE channelHandle; + HANDLE eventHandle; + + UINT32 expectedBytes; + BOOL waitingHeaders; + wStream *inputStream; + wStream *outputStream; + + UINT16 currentMsgType; + + RDPINPUT_TOUCH_EVENT touchEvent; + + enum RdpEiState automataState; +}; + + +RdpeiServerContext* rdpei_server_context_new(HANDLE vcm) +{ + RdpeiServerContext *ret = calloc(1, sizeof(*ret)); + RdpeiServerPrivate *priv; + + if (!ret) + return NULL; + + ret->priv = priv = calloc(1, sizeof(*ret->priv)); + if (!priv) + goto out_free; + + priv->inputStream = Stream_New(NULL, 256); + if (!priv->inputStream) + goto out_free_priv; + + priv->outputStream = Stream_New(NULL, 200); + if (!priv->inputStream) + goto out_free_input_stream; + + ret->vcm = vcm; + rdpei_server_context_reset(ret); + return ret; + +out_free_input_stream: + Stream_Free(priv->inputStream, TRUE); +out_free_priv: + free(ret->priv); +out_free: + free(ret); + return NULL; +} + +int rdpei_server_init(RdpeiServerContext *context) +{ + void *buffer = NULL; + DWORD bytesReturned; + RdpeiServerPrivate *priv = context->priv; + + priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + if (!priv->channelHandle) + { + fprintf(stderr, "%s: unable to open channel\n", __FUNCTION__); + return -1; + } + + if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) + { + fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", + __FUNCTION__, bytesReturned); + if (buffer) + WTSFreeMemory(buffer); + goto out_close; + } + CopyMemory(&priv->eventHandle, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + + return 0; + +out_close: + WTSVirtualChannelClose(priv->channelHandle); + return -1; +} + + +void rdpei_server_context_reset(RdpeiServerContext *context) +{ + RdpeiServerPrivate *priv = context->priv; + + priv->expectedBytes = RDPINPUT_HEADER_LENGTH; + priv->waitingHeaders = TRUE; + priv->automataState = STATE_INITIAL; + Stream_SetPosition(priv->inputStream, 0); +} + +void rdpei_server_context_free(RdpeiServerContext* context) +{ + Stream_Free(context->priv->inputStream, TRUE); + free(context->priv); + free(context); +} + +HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context) +{ + return context->priv->eventHandle; +} + + +static int read_cs_ready_message(RdpeiServerContext *context, wStream *s) +{ + if (Stream_GetRemainingLength(s) < 10) + return -1; + + Stream_Read_UINT32(s, context->protocolFlags); + Stream_Read_UINT32(s, context->clientVersion); + Stream_Read_UINT16(s, context->maxTouchPoints); + + switch (context->clientVersion) + { + case RDPINPUT_PROTOCOL_V10: + case RDPINPUT_PROTOCOL_V101: + break; + default: + fprintf(stderr, "%s: unhandled RPDEI protocol version 0x%x\n", __FUNCTION__, context->clientVersion); + break; + } + + if (context->onClientReady) + context->onClientReady(context); + return 0; +} + +static int read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDPINPUT_CONTACT_DATA *contactData) +{ + if (Stream_GetRemainingLength(s) < 1) + return -1; + + Stream_Read_UINT8(s, contactData->contactId); + if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) || + !rdpei_read_4byte_signed(s, &contactData->x) || + !rdpei_read_4byte_signed(s, &contactData->y) || + !rdpei_read_4byte_unsigned(s, &contactData->contactFlags)) + return -1; + + if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT) + { + if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) || + !rdpei_read_2byte_signed(s, &contactData->contactRectTop) || + !rdpei_read_2byte_signed(s, &contactData->contactRectRight) || + !rdpei_read_2byte_signed(s, &contactData->contactRectBottom)) + return -1; + } + + if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) && + !rdpei_read_4byte_unsigned(s, &contactData->orientation)) + return -1; + + if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) && + !rdpei_read_4byte_unsigned(s, &contactData->pressure)) + return -1; + + return 0; +} + +static int read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_TOUCH_FRAME *frame) +{ + int i; + RDPINPUT_CONTACT_DATA *contact; + + if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) || !rdpei_read_8byte_unsigned(s, &frame->frameOffset)) + return -1; + + frame->contacts = contact = calloc(frame->contactCount, sizeof(RDPINPUT_CONTACT_DATA)); + if (!frame->contacts) + return -1; + + for (i = 0; i < frame->contactCount; i++, contact++) + { + if (read_touch_contact_data(context, s, contact) < 0) + { + frame->contactCount = i; + goto out_cleanup; + } + } + return 0; + +out_cleanup: + touch_frame_reset(frame); + return -1; +} + +static int read_touch_event(RdpeiServerContext *context, wStream *s) +{ + UINT32 frameCount; + int i, ret; + RDPINPUT_TOUCH_EVENT *event = &context->priv->touchEvent; + RDPINPUT_TOUCH_FRAME *frame; + + ret = -1; + if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) || !rdpei_read_2byte_unsigned(s, &frameCount)) + return -1; + + event->frameCount = frameCount; + event->frames = frame = calloc(event->frameCount, sizeof(RDPINPUT_TOUCH_FRAME)); + if (!event->frames) + return -1; + + for (i = 0; i < frameCount; i++, frame++) + { + if (read_touch_frame(context, s, frame) < 0) + { + event->frameCount = i; + goto out_cleanup; + } + } + + if (context->onTouchEvent) + context->onTouchEvent(context, event); + + ret = 0; + +out_cleanup: + touch_event_reset(event); + return ret; +} + + +static int read_dismiss_hovering_contact(RdpeiServerContext *context, wStream *s) { + BYTE contactId; + if (Stream_GetRemainingLength(s) < 1) + return -1; + + Stream_Read_UINT8(s, contactId); + if (context->onTouchReleased) + context->onTouchReleased(context, contactId); + return 0; +} + + +int rdpei_server_handle_messages(RdpeiServerContext *context) { + DWORD bytesReturned; + RdpeiServerPrivate *priv = context->priv; + wStream *s = priv->inputStream; + + if (!WTSVirtualChannelRead(priv->channelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return -1; + + fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__); + return 0; + } + priv->expectedBytes -= bytesReturned; + Stream_Seek(s, bytesReturned); + + if (priv->expectedBytes) + return 1; + + Stream_SealLength(s); + Stream_SetPosition(s, 0); + + if (priv->waitingHeaders) + { + UINT32 pduLen; + + /* header case */ + Stream_Read_UINT16(s, priv->currentMsgType); + Stream_Read_UINT16(s, pduLen); + + if (pduLen < RDPINPUT_HEADER_LENGTH) + { + fprintf(stderr, "%s: invalid pduLength %d\n", __FUNCTION__, pduLen); + return -1; + } + priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH; + priv->waitingHeaders = FALSE; + Stream_SetPosition(s, 0); + if (priv->expectedBytes) + { + Stream_EnsureCapacity(s, priv->expectedBytes); + return 1; + } + } + + /* when here we have the header + the body */ + switch (priv->currentMsgType) + { + case EVENTID_CS_READY: + if (priv->automataState != STATE_WAITING_CLIENT_READY) + { + fprintf(stderr, "%s: not expecting a CS_READY packet in this state(%d)\n", __FUNCTION__, (int)priv->automataState); + return 0; + } + + if (read_cs_ready_message(context, s) < 0) + return 0; + break; + + case EVENTID_TOUCH: + if (read_touch_event(context, s) < 0) + { + fprintf(stderr, "%s: error in touch event packet\n", __FUNCTION__); + return 0; + } + break; + case EVENTID_DISMISS_HOVERING_CONTACT: + if (read_dismiss_hovering_contact(context, s) < 0) + { + fprintf(stderr, "%s: error reading read_dismiss_hovering_contact\n", __FUNCTION__); + return 0; + } + break; + default: + fprintf(stderr, "%s: unexpected message type 0x%x\n", __FUNCTION__, priv->currentMsgType); + } + + Stream_SetPosition(s, 0); + priv->waitingHeaders = TRUE; + priv->expectedBytes = RDPINPUT_HEADER_LENGTH; + return 1; +} + + +int rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version) +{ + ULONG written; + RdpeiServerPrivate *priv = context->priv; + + if (priv->automataState != STATE_INITIAL) + { + fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState); + return -1; + } + + Stream_SetPosition(priv->outputStream, 0); + Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + + Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + Stream_Write_UINT32(priv->outputStream, version); + + if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), + Stream_GetPosition(priv->outputStream), &written)) + { + fprintf(stderr, "%s: error writing ready message\n", __FUNCTION__); + return -1; + } + + priv->automataState = STATE_WAITING_CLIENT_READY; + return 0; +} + +int rdpei_server_suspend(RdpeiServerContext *context) +{ + ULONG written; + RdpeiServerPrivate *priv = context->priv; + + switch (priv->automataState) + { + case STATE_SUSPENDED: + fprintf(stderr, "%s: already suspended\n", __FUNCTION__); + return 0; + case STATE_WAITING_FRAME: + break; + default: + fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState); + return -1; + } + + Stream_SetPosition(priv->outputStream, 0); + Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), + Stream_GetPosition(priv->outputStream), &written)) + { + fprintf(stderr, "%s: error writing suspendTouch message\n", __FUNCTION__); + return -1; + } + + priv->automataState = STATE_SUSPENDED; + return 0; +} + + +int rdpei_server_resume(RdpeiServerContext *context) +{ + ULONG written; + RdpeiServerPrivate *priv = context->priv; + + switch (priv->automataState) + { + case STATE_WAITING_FRAME: + fprintf(stderr, "%s: not suspended\n", __FUNCTION__); + return 0; + case STATE_SUSPENDED: + break; + default: + fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState); + return -1; + } + + Stream_SetPosition(priv->outputStream, 0); + Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH); + + if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), + Stream_GetPosition(priv->outputStream), &written)) + { + fprintf(stderr, "%s: error writing resumeTouch message\n", __FUNCTION__); + return -1; + } + + priv->automataState = STATE_WAITING_FRAME; + return 0; +} + diff --git a/channels/rdpei/server/rdpei_main.h b/channels/rdpei/server/rdpei_main.h new file mode 100644 index 000000000..44dd03ed3 --- /dev/null +++ b/channels/rdpei/server/rdpei_main.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel server-side implementation + * + * Copyright 2014 David Fort + * + * 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 __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ +#define __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ + +#include +#include +#include + + +#endif /* FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ */ + diff --git a/channels/server/channels.c b/channels/server/channels.c index cac4243bd..cb312c849 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -45,9 +45,10 @@ #include #include #include +#include #include -void freerdp_channels_dummy() +void freerdp_channels_dummy() { audin_server_context_new(NULL); audin_server_context_free(NULL); @@ -66,6 +67,9 @@ void freerdp_channels_dummy() drdynvc_server_context_new(NULL); drdynvc_server_context_free(NULL); + + rdpei_server_context_new(NULL); + rdpei_server_context_free(NULL); } /** diff --git a/include/freerdp/channels/rdpei.h b/include/freerdp/channels/rdpei.h new file mode 100644 index 000000000..ac76bf364 --- /dev/null +++ b/include/freerdp/channels/rdpei.h @@ -0,0 +1,91 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel common definitions + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 Thincast Technologies Gmbh. + * Copyright 2014 David FORT + * + * 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 __FREERDP_CHANNEL_RDPEI_H_ +#define __FREERDP_CHANNEL_RDPEI_H_ + +#include + +#define RDPINPUT_HEADER_LENGTH 6 + +#define RDPEI_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Input" + +/** @brief protocol version */ +enum { + RDPINPUT_PROTOCOL_V10 = 0x00010000, + RDPINPUT_PROTOCOL_V101 = 0x00010001 +}; + +/* Client Ready Flags */ +#define READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001 +#define READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002 + + +#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 + +/** @brief a contact point */ +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; + +/** @brief a frame containing contact points */ +struct _RDPINPUT_TOUCH_FRAME +{ + UINT32 contactCount; + UINT64 frameOffset; + RDPINPUT_CONTACT_DATA* contacts; +}; +typedef struct _RDPINPUT_TOUCH_FRAME RDPINPUT_TOUCH_FRAME; + + +/** @brief a touch event with some frames*/ +struct _RDPINPUT_TOUCH_EVENT +{ + UINT32 encodeTime; + UINT16 frameCount; + RDPINPUT_TOUCH_FRAME* frames; +}; +typedef struct _RDPINPUT_TOUCH_EVENT RDPINPUT_TOUCH_EVENT; + + +#endif /* __FREERDP_CHANNEL_RDPEI_H_ */ + diff --git a/include/freerdp/client/rdpei.h b/include/freerdp/client/rdpei.h index 76b889829..1dec61313 100644 --- a/include/freerdp/client/rdpei.h +++ b/include/freerdp/client/rdpei.h @@ -20,51 +20,15 @@ #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; +#include /** * Client Interface */ -#define RDPEI_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Input" - typedef struct _rdpei_client_context RdpeiClientContext; -typedef int (*pcRdpeiGetVersion)(RdpeiClientContext* context); -typedef int (*pcRdpeiAddContact)(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact); +typedef int (*pcRdpeiGetVersion)(RdpeiClientContext* context);typedef int (*pcRdpeiAddContact)(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact); typedef int (*pcRdpeiTouchBegin)(RdpeiClientContext* context, int externalId, int x, int y); typedef int (*pcRdpeiTouchUpdate)(RdpeiClientContext* context, int externalId, int x, int y); diff --git a/include/freerdp/server/rdpei.h b/include/freerdp/server/rdpei.h new file mode 100644 index 000000000..c447b0d73 --- /dev/null +++ b/include/freerdp/server/rdpei.h @@ -0,0 +1,70 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Extended Input channel server-side definitions + * + * Copyright 2014 Thincast Technologies Gmbh. + * Copyright 2014 David FORT + * + * 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 __FREERDP_CHANNEL_RDPEI_SERVER_H__ +#define __FREERDP_CHANNEL_RDPEI_SERVER_H__ + +#include +#include + + +typedef struct _rdpei_server_context RdpeiServerContext; +typedef struct _rdpei_server_private RdpeiServerPrivate; + +struct _rdpei_server_context +{ + HANDLE vcm; + + RdpeiServerPrivate* priv; + + UINT32 clientVersion; + UINT16 maxTouchPoints; + UINT32 protocolFlags; + + /** callbacks that can be set by the user */ + void (*onClientReady)(RdpeiServerContext *context); + void (*onTouchEvent)(RdpeiServerContext *context, RDPINPUT_TOUCH_EVENT *touchEvent); + void (*onTouchReleased)(RdpeiServerContext *context, BYTE contactId); + + void *user_data; /* user data, useful for callbacks */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API RdpeiServerContext* rdpei_server_context_new(HANDLE vcm); +FREERDP_API void rdpei_server_context_reset(RdpeiServerContext *context); +FREERDP_API void rdpei_server_context_free(RdpeiServerContext* context); +FREERDP_API HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context); +FREERDP_API int rdpei_server_init(RdpeiServerContext *context); +FREERDP_API int rdpei_server_handle_messages(RdpeiServerContext *context); + +FREERDP_API int rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version); +FREERDP_API int rdpei_server_suspend(RdpeiServerContext *context); +FREERDP_API int rdpei_server_resume(RdpeiServerContext *context); + +#ifdef __cplusplus +} +#endif + + + +#endif /* __FREERDP_CHANNEL_RDPEI_SERVER_H__ */