From e3a4d125cd5981752961a33b8a17b6295c569fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 8 May 2013 23:18:42 -0400 Subject: [PATCH] channels/rdpei: start implementing multitouch --- channels/rdpei/client/CMakeLists.txt | 6 +- channels/rdpei/client/rdpei_common.c | 590 +++++++++++++++++++++++++++ channels/rdpei/client/rdpei_common.h | 27 ++ channels/rdpei/client/rdpei_main.c | 75 +++- channels/rdpei/client/rdpei_main.h | 13 + 5 files changed, 708 insertions(+), 3 deletions(-) create mode 100644 channels/rdpei/client/rdpei_common.c create mode 100644 channels/rdpei/client/rdpei_common.h diff --git a/channels/rdpei/client/CMakeLists.txt b/channels/rdpei/client/CMakeLists.txt index 8ad191ccc..b3aacdcb2 100644 --- a/channels/rdpei/client/CMakeLists.txt +++ b/channels/rdpei/client/CMakeLists.txt @@ -1,7 +1,7 @@ # FreeRDP: A Remote Desktop Protocol Implementation # FreeRDP cmake build script # -# Copyright 2012 Marc-Andre Moreau +# 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. @@ -19,7 +19,9 @@ define_channel_client("rdpei") set(${MODULE_PREFIX}_SRCS rdpei_main.c - rdpei_main.h) + rdpei_main.h + rdpei_common.c + rdpei_common.h) include_directories(..) diff --git a/channels/rdpei/client/rdpei_common.c b/channels/rdpei/client/rdpei_common.c new file mode 100644 index 000000000..c81237c36 --- /dev/null +++ b/channels/rdpei/client/rdpei_common.c @@ -0,0 +1,590 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Input Virtual Channel Extension + * + * 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 +#include + +#include "rdpei_common.h" + +BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value) +{ + BYTE byte; + + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + Stream_Read_UINT8(s, byte); + + if (byte & 0x80) + { + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + + *value = (byte & 0x7F) << 8; + Stream_Read_UINT8(s, byte); + *value |= byte; + } + else + { + *value = (byte & 0x7F); + } + + return TRUE; +} + +BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value) +{ + BYTE byte; + + if (value > 0x7FFF) + return FALSE; + + if (value >= 0x7F) + { + byte = ((value & 0x7F00) >> 8); + Stream_Write_UINT8(s, byte | 0x80); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else + { + byte = (value & 0x7F); + Stream_Write_UINT8(s, byte); + } + + return TRUE; +} + +BOOL rdpei_read_2byte_signed(wStream* s, INT32* value) +{ + BYTE byte; + BOOL negative; + + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + + Stream_Read_UINT8(s, byte); + + negative = (byte & 0x40) ? TRUE : FALSE; + + *value = (byte & 0x3F); + + if (byte & 0x80) + { + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + + Stream_Read_UINT8(s, byte); + *value = (*value << 8) | byte; + } + + if (negative) + *value *= -1; + + return TRUE; +} + +BOOL rdpei_write_2byte_signed(wStream* s, INT32 value) +{ + BYTE byte; + BOOL negative = FALSE; + + if (value < 0) + { + negative = TRUE; + value *= -1; + } + + if (value > 0x3FFF) + return FALSE; + + if (value >= 0x3F) + { + byte = ((value & 0x3F00) >> 8); + + if (negative) + byte |= 0x40; + + Stream_Write_UINT8(s, byte | 0x80); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else + { + byte = (value & 0x3F); + + if (negative) + byte |= 0x40; + + Stream_Write_UINT8(s, byte); + } + + return TRUE; +} + +BOOL rdpei_read_4byte_unsigned(wStream* s, UINT32* value) +{ + BYTE byte; + BYTE count; + + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + + Stream_Read_UINT8(s, byte); + + count = (byte & 0xC0) >> 6; + + if (Stream_GetRemainingLength(s) < count) + return FALSE; + + switch (count) + { + case 0: + *value = (byte & 0x3F); + break; + + case 1: + *value = (byte & 0x3F) << 8; + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 2: + *value = (byte & 0x3F) << 16; + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 3: + *value = (byte & 0x3F) << 24; + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + default: + break; + } + + return TRUE; +} + +BOOL rdpei_write_4byte_unsigned(wStream* s, UINT32 value) +{ + BYTE byte; + + if (value <= 0x3F) + { + Stream_Write_UINT8(s, value); + } + else if (value <= 0x3FFF) + { + byte = (value >> 8) & 0x3F; + Stream_Write_UINT8(s, byte | 0x40); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x3FFFFF) + { + byte = (value >> 16) & 0x3F; + Stream_Write_UINT8(s, byte | 0x80); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x3FFFFF) + { + byte = (value >> 24) & 0x3F; + Stream_Write_UINT8(s, byte | 0xC0); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else + { + return FALSE; + } + + return TRUE; +} + +BOOL rdpei_read_4byte_signed(wStream* s, INT32* value) +{ + BYTE byte; + BYTE count; + BOOL negative; + + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + + Stream_Read_UINT8(s, byte); + + count = (byte & 0xC0) >> 6; + negative = (byte & 0x20); + + if (Stream_GetRemainingLength(s) < count) + return FALSE; + + switch (count) + { + case 0: + *value = (byte & 0x1F); + break; + + case 1: + *value = (byte & 0x1F) << 8; + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 2: + *value = (byte & 0x1F) << 16; + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 3: + *value = (byte & 0x1F) << 24; + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + default: + break; + } + + if (negative) + *value *= -1; + + return TRUE; +} + +BOOL rdpei_write_4byte_signed(wStream* s, INT32 value) +{ + BYTE byte; + BOOL negative = FALSE; + + if (value < 0) + { + negative = TRUE; + value *= -1; + } + + if (value <= 0x1F) + { + byte = value & 0x1F; + + if (negative) + byte |= 0x20; + + Stream_Write_UINT8(s, value); + } + else if (value <= 0x1FFF) + { + byte = (value >> 8) & 0x1F; + + if (negative) + byte |= 0x20; + + Stream_Write_UINT8(s, byte | 0x40); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFF) + { + byte = (value >> 16) & 0x1F; + + if (negative) + byte |= 0x20; + + Stream_Write_UINT8(s, byte | 0x80); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFF) + { + byte = (value >> 24) & 0x1F; + + if (negative) + byte |= 0x20; + + Stream_Write_UINT8(s, byte | 0xC0); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else + { + return FALSE; + } + + return TRUE; +} + +BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value) +{ + BYTE byte; + BYTE count; + + if (Stream_GetRemainingLength(s) < 1) + return FALSE; + + Stream_Read_UINT8(s, byte); + + count = (byte & 0xE0) >> 5; + + if (Stream_GetRemainingLength(s) < count) + return FALSE; + + switch (count) + { + case 0: + *value = (byte & 0x1F); + break; + + case 1: + *value = (byte & 0x1F) << 8; + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 2: + *value = (byte & 0x1F) << 16; + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 3: + *value = (byte & 0x1F) << 24; + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 4: + *value = (byte & 0x1F) << 32; + Stream_Read_UINT8(s, byte); + *value |= (byte << 24); + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 5: + *value = (byte & 0x1F) << 40; + Stream_Read_UINT8(s, byte); + *value |= (byte << 32); + Stream_Read_UINT8(s, byte); + *value |= (byte << 24); + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 6: + *value = (byte & 0x1F) << 48; + Stream_Read_UINT8(s, byte); + *value |= (byte << 40); + Stream_Read_UINT8(s, byte); + *value |= (byte << 32); + Stream_Read_UINT8(s, byte); + *value |= (byte << 24); + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + case 7: + *value = (byte & 0x1F) << 56; + Stream_Read_UINT8(s, byte); + *value |= (byte << 48); + Stream_Read_UINT8(s, byte); + *value |= (byte << 40); + Stream_Read_UINT8(s, byte); + *value |= (byte << 32); + Stream_Read_UINT8(s, byte); + *value |= (byte << 24); + Stream_Read_UINT8(s, byte); + *value |= (byte << 16); + Stream_Read_UINT8(s, byte); + *value |= (byte << 8); + Stream_Read_UINT8(s, byte); + *value |= byte; + break; + + default: + break; + } + + return TRUE; +} + +BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) +{ + BYTE byte; + BYTE count; + + if (value <= 0x1F) + { + count = 0; + byte = value & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + } + else if (value <= 0x1FFF) + { + count = 1; + byte = (value >> 8) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFF) + { + count = 2; + byte = (value >> 16) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFF) + { + count = 3; + byte = (value >> 24) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFFFF) + { + count = 4; + byte = (value >> 32) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value >> 24) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFFFFFF) + { + count = 5; + byte = (value >> 40) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value >> 32) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 24) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFFFFFFFF) + { + count = 6; + byte = (value >> 48) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value >> 40) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 32) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 24) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else if (value <= 0x1FFFFFFFFFFFFF) + { + count = 7; + byte = (value >> 56) & 0x1F; + Stream_Write_UINT8(s, byte | (count << 5)); + byte = (value >> 48) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 40) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 32) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 24) & 0x1F; + Stream_Write_UINT8(s, byte); + byte = (value >> 16) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value >> 8) & 0xFF; + Stream_Write_UINT8(s, byte); + byte = (value & 0xFF); + Stream_Write_UINT8(s, byte); + } + else + { + return FALSE; + } + + return TRUE; +} diff --git a/channels/rdpei/client/rdpei_common.h b/channels/rdpei/client/rdpei_common.h new file mode 100644 index 000000000..0ed59b0a8 --- /dev/null +++ b/channels/rdpei/client/rdpei_common.h @@ -0,0 +1,27 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Input Virtual Channel Extension + * + * 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 FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H +#define FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H + +#include +#include + +#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H */ + diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 2f866d7ab..130ccf50e 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -26,11 +26,12 @@ #include #include +#include #include #include -#include +#include "rdpei_common.h" #include "rdpei_main.h" @@ -61,11 +62,83 @@ struct _RDPEI_PLUGIN RDPEI_LISTENER_CALLBACK* listener_callback; }; +const char* RDPEI_EVENTID_STRINGS[] = +{ + "", + "EVENTID_SC_READY", + "EVENTID_CS_READY", + "EVENTID_TOUCH", + "EVENTID_SUSPEND_TOUCH", + "EVENTID_RESUME_TOUCH", + "EVENTID_DISMISS_HOVERING_CONTACT" +}; + +int rdpei_recv_sc_ready_pdu(wStream* s) +{ + UINT32 protocolVersion; + + Stream_Read_UINT32(s, protocolVersion); /* protocolVersion (4 bytes) */ + + if (protocolVersion != RDPINPUT_PROTOCOL_V1) + { + printf("Unknown [MS-RDPEI] protocolVersion: 0x%08X\n", protocolVersion); + return -1; + } + + return 0; +} + +int rdpei_recv_pdu(wStream* s) +{ + UINT16 eventId; + UINT32 pduLength; + + Stream_Read_UINT16(s, eventId); /* eventId (2 bytes) */ + Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */ + + printf("rdpei_recv_pdu: eventId: %d (%s) length: %d\n", + eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength); + + switch (eventId) + { + case EVENTID_SC_READY: + rdpei_recv_sc_ready_pdu(s); + break; + + case EVENTID_CS_READY: + break; + + case EVENTID_TOUCH: + break; + + case EVENTID_SUSPEND_TOUCH: + break; + + case EVENTID_RESUME_TOUCH: + break; + + case EVENTID_DISMISS_HOVERING_CONTACT: + break; + + default: + break; + } + + return 0; +} + static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer) { + wStream* s; int status = 0; //RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback; + s = Stream_New(pBuffer, cbSize); + + status = rdpei_recv_pdu(s); + + Stream_Free(s, FALSE); + return status; } diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index ca233b3a8..20e207f94 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -29,6 +29,19 @@ #include #include +/* Protocol Version */ + +#define RDPINPUT_PROTOCOL_V1 0x00010000 + +/* 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 + #ifdef WITH_DEBUG_DVC #define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) #else