diff --git a/channels/rdpei/client/rdpei_common.c b/channels/rdpei/client/rdpei_common.c index c81237c36..e0b758a04 100644 --- a/channels/rdpei/client/rdpei_common.c +++ b/channels/rdpei/client/rdpei_common.c @@ -32,6 +32,7 @@ BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value) if (Stream_GetRemainingLength(s) < 1) return FALSE; + Stream_Read_UINT8(s, byte); if (byte & 0x80) diff --git a/channels/rdpei/client/rdpei_common.h b/channels/rdpei/client/rdpei_common.h index 0ed59b0a8..293919f67 100644 --- a/channels/rdpei/client/rdpei_common.h +++ b/channels/rdpei/client/rdpei_common.h @@ -23,5 +23,16 @@ #include #include +BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value); +BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value); +BOOL rdpei_read_2byte_signed(wStream* s, INT32* value); +BOOL rdpei_write_2byte_signed(wStream* s, INT32 value); +BOOL rdpei_read_4byte_unsigned(wStream* s, UINT32* value); +BOOL rdpei_write_4byte_unsigned(wStream* s, UINT32 value); +BOOL rdpei_read_4byte_signed(wStream* s, INT32* value); +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 */ diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 130ccf50e..bf1198e1c 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -73,7 +73,130 @@ const char* RDPEI_EVENTID_STRINGS[] = "EVENTID_DISMISS_HOVERING_CONTACT" }; -int rdpei_recv_sc_ready_pdu(wStream* s) +int rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, UINT16 eventId, UINT32 pduLength) +{ + int status; + + Stream_SetPosition(s, 0); + Stream_Write_UINT16(s, eventId); /* eventId (2 bytes) */ + Stream_Write_UINT32(s, pduLength); /* pduLength (4 bytes) */ + Stream_SetPosition(s, Stream_Length(s)); + + printf("rdpei_send_pdu: eventId: %d (%s) length: %d\n", + eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength); + + status = callback->channel->Write(callback->channel, + Stream_Length(s), Stream_Buffer(s), NULL); + + return status; +} + +int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) +{ + int status; + wStream* s; + UINT32 flags; + UINT32 pduLength; + UINT16 maxTouchContacts; + + flags = 0; + flags |= READY_FLAGS_SHOW_TOUCH_VISUALS; + //flags |= READY_FLAGS_DISABLE_TIMESTAMP_INJECTION; + + maxTouchContacts = 10; + + pduLength = RDPINPUT_HEADER_LENGTH + 10; + s = Stream_New(NULL, pduLength); + Stream_Seek(s, RDPINPUT_HEADER_LENGTH); + + Stream_Write_UINT32(s, flags); /* flags (4 bytes) */ + Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V1); /* protocolVersion (4 bytes) */ + Stream_Write_UINT16(s, maxTouchContacts); /* maxTouchContacts (2 bytes) */ + + Stream_SealLength(s); + + status = rdpei_send_pdu(callback, s, EVENTID_CS_READY, pduLength); + Stream_Free(s, TRUE); + + return status; +} + +int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) +{ + int index; + RDPINPUT_CONTACT_DATA* contact; + + rdpei_write_2byte_unsigned(s, frame->contactCount); + rdpei_write_8byte_unsigned(s, frame->frameOffset); + + Stream_EnsureRemainingCapacity(s, frame->contactCount * 32); + + for (index = 0; index < frame->contactCount; index++) + { + contact = &frame->contacts[index]; + + Stream_Write_UINT8(s, contact->contactId); + rdpei_write_2byte_unsigned(s, contact->fieldsPresent); + rdpei_write_4byte_signed(s, contact->x); + rdpei_write_4byte_signed(s, contact->y); + rdpei_write_4byte_unsigned(s, contact->contactFlags); + + if (contact->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT) + { + rdpei_write_2byte_signed(s, contact->contactRectLeft); + rdpei_write_2byte_signed(s, contact->contactRectTop); + rdpei_write_2byte_signed(s, contact->contactRectRight); + rdpei_write_2byte_signed(s, contact->contactRectBottom); + } + + if (contact->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) + { + rdpei_write_4byte_unsigned(s, contact->orientation); + } + + if (contact->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) + { + rdpei_write_4byte_unsigned(s, contact->pressure); + } + } + + return 0; +} + +int rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback) +{ + int status; + wStream* s; + UINT32 pduLength; + UINT32 encodeTime; + UINT16 frameCount; + RDPINPUT_TOUCH_FRAME frame; + RDPINPUT_CONTACT_DATA contact; + + encodeTime = 123; + 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); + + Stream_SealLength(s); + pduLength = Stream_Length(s); + + status = rdpei_send_pdu(callback, s, EVENTID_TOUCH, pduLength); + Stream_Free(s, TRUE); + + return status; +} + +int rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { UINT32 protocolVersion; @@ -88,7 +211,17 @@ int rdpei_recv_sc_ready_pdu(wStream* s) return 0; } -int rdpei_recv_pdu(wStream* s) +int rdpei_recv_suspend_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) +{ + return 0; +} + +int rdpei_recv_resume_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) +{ + return 0; +} + +int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 eventId; UINT32 pduLength; @@ -102,22 +235,16 @@ int rdpei_recv_pdu(wStream* s) switch (eventId) { case EVENTID_SC_READY: - rdpei_recv_sc_ready_pdu(s); - break; - - case EVENTID_CS_READY: - break; - - case EVENTID_TOUCH: + rdpei_recv_sc_ready_pdu(callback, s); + rdpei_send_cs_ready_pdu(callback); break; case EVENTID_SUSPEND_TOUCH: + rdpei_recv_suspend_touch_pdu(callback, s); break; case EVENTID_RESUME_TOUCH: - break; - - case EVENTID_DISMISS_HOVERING_CONTACT: + rdpei_recv_resume_touch_pdu(callback, s); break; default: @@ -131,11 +258,11 @@ static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, { wStream* s; int status = 0; - //RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback; + RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback; s = Stream_New(pBuffer, cbSize); - status = rdpei_recv_pdu(s); + status = rdpei_recv_pdu(callback, s); Stream_Free(s, FALSE); diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index 20e207f94..42247ec39 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -29,10 +29,52 @@ #include #include +#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 +/* 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