diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index 4bae7d3e6..27bb83b0b 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -1027,6 +1027,8 @@ int xfreerdp_run(freerdp* instance) fd_set wfds_set; int fd_msg_event; HANDLE msg_event; + int fd_evt_event; + HANDLE evt_event; int select_status; rdpChannels* channels; struct timeval timeout; @@ -1059,6 +1061,12 @@ int xfreerdp_run(freerdp* instance) if (msg_event) fd_msg_event = GetEventFileDescriptor(msg_event); + fd_evt_event = -1; + evt_event = freerdp_get_input_queue_event_handle(instance); + + if (evt_event) + fd_evt_event = GetEventFileDescriptor(evt_event); + while (!xfi->disconnect && !freerdp_shall_disconnect(instance)) { rcount = 0; @@ -1086,6 +1094,9 @@ int xfreerdp_run(freerdp* instance) if (fd_msg_event > 0) rfds[rcount++] = (void*) (long) fd_msg_event; + if (fd_evt_event > 0) + rfds[rcount++] = (void*) (long) fd_evt_event; + max_fds = 0; FD_ZERO(&rfds_set); FD_ZERO(&wfds_set); @@ -1144,6 +1155,9 @@ int xfreerdp_run(freerdp* instance) if (fd_msg_event > 0) freerdp_process_messages(instance); + + if (fd_evt_event > 0) + freerdp_process_input(instance); } FILE *fin = fopen("/tmp/tsmf.tid", "rt"); diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index f3dc3eccd..b80adaf0d 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -199,6 +199,9 @@ FREERDP_API BOOL freerdp_check_fds(freerdp* instance); FREERDP_API int freerdp_process_messages(freerdp* instance); FREERDP_API HANDLE freerdp_get_message_queue_event_handle(freerdp* instance); +FREERDP_API HANDLE freerdp_get_input_queue_event_handle(freerdp* instance); +FREERDP_API int freerdp_process_input(freerdp* instance); + FREERDP_API UINT32 freerdp_error_info(freerdp* instance); FREERDP_API void freerdp_get_version(int* major, int* minor, int* revision); diff --git a/include/freerdp/input.h b/include/freerdp/input.h index 9ea47caab..8143ad74f 100644 --- a/include/freerdp/input.h +++ b/include/freerdp/input.h @@ -26,6 +26,9 @@ typedef struct rdp_input rdpInput; #include #include +#include +#include + /* keyboard Flags */ #define KBD_FLAGS_EXTENDED 0x0100 #define KBD_FLAGS_DOWN 0x4000 @@ -54,6 +57,11 @@ typedef struct rdp_input rdpInput; #define RDP_CLIENT_INPUT_PDU_HEADER_LENGTH 4 +/* defined inside libfreerdp-core */ +typedef struct rdp_event rdpEvent; + +/* Input Interface */ + typedef void (*pSynchronizeEvent)(rdpInput* input, UINT32 flags); typedef void (*pKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); typedef void (*pUnicodeKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); @@ -72,6 +80,12 @@ struct rdp_input pMouseEvent MouseEvent; /* 19 */ pExtendedMouseEvent ExtendedMouseEvent; /* 20 */ UINT32 paddingB[32 - 21]; /* 21 */ + + /* Internal */ + + BOOL asynchronous; + rdpEvent* event; + wMessageQueue* queue; }; #ifdef __cplusplus diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt index 1918c8940..7832d35ce 100644 --- a/libfreerdp/core/CMakeLists.txt +++ b/libfreerdp/core/CMakeLists.txt @@ -64,6 +64,8 @@ set(${MODULE_PREFIX}_SRCS info.h input.c input.h + event.c + event.h license.c license.h errinfo.c diff --git a/libfreerdp/core/event.c b/libfreerdp/core/event.c new file mode 100644 index 000000000..e0dbe23b4 --- /dev/null +++ b/libfreerdp/core/event.c @@ -0,0 +1,212 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Asynchronous Event Queue + * + * Copyright 2012 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 "event.h" + +#include +#include + +/* Input */ + +static void event_SynchronizeEvent(rdpInput* input, UINT32 flags) +{ + MessageQueue_Post(input->queue, (void*) input, + MakeMessageId(Input, SynchronizeEvent), (void*) (size_t) flags, NULL); +} + +static void event_KeyboardEvent(rdpInput* input, UINT16 flags, UINT16 code) +{ + MessageQueue_Post(input->queue, (void*) input, + MakeMessageId(Input, KeyboardEvent), (void*) (size_t) flags, (void*) (size_t) code); +} + +static void event_UnicodeKeyboardEvent(rdpInput* input, UINT16 flags, UINT16 code) +{ + MessageQueue_Post(input->queue, (void*) input, + MakeMessageId(Input, UnicodeKeyboardEvent), (void*) (size_t) flags, (void*) (size_t) code); +} + +static void event_MouseEvent(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + UINT32 pos = (x << 16) | y; + + MessageQueue_Post(input->queue, (void*) input, + MakeMessageId(Input, MouseEvent), (void*) (size_t) flags, (void*) (size_t) pos); +} + +static void event_ExtendedMouseEvent(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + UINT32 pos = (x << 16) | y; + + MessageQueue_Post(input->queue, (void*) input, + MakeMessageId(Input, ExtendedMouseEvent), (void*) (size_t) flags, (void*) (size_t) pos); +} + +/* Event Queue */ + +int event_process_input_class(rdpEvent* event, wMessage* msg, int type) +{ + int status = 0; + + switch (type) + { + case Input_SynchronizeEvent: + IFCALL(event->SynchronizeEvent, msg->context, (UINT32) (size_t) msg->wParam); + break; + + case Input_KeyboardEvent: + IFCALL(event->KeyboardEvent, msg->context, (UINT16) (size_t) msg->wParam, (UINT16) (size_t) msg->lParam); + break; + + case Input_UnicodeKeyboardEvent: + IFCALL(event->UnicodeKeyboardEvent, msg->context, (UINT16) (size_t) msg->wParam, (UINT16) (size_t) msg->lParam); + break; + + case Input_MouseEvent: + { + UINT32 pos; + UINT16 x, y; + + pos = (UINT32) (size_t) msg->lParam; + x = ((pos & 0xFFFF0000) >> 16); + y = (pos & 0x0000FFFF); + + IFCALL(event->MouseEvent, msg->context, (UINT16) (size_t) msg->wParam, x, y); + } + break; + + case Input_ExtendedMouseEvent: + { + UINT32 pos; + UINT16 x, y; + + pos = (UINT32) (size_t) msg->lParam; + x = ((pos & 0xFFFF0000) >> 16); + y = (pos & 0x0000FFFF); + + IFCALL(event->ExtendedMouseEvent, msg->context, (UINT16) (size_t) msg->wParam, x, y); + } + break; + + default: + status = -1; + break; + } + + return status; +} + + +int event_process_class(rdpEvent* event, wMessage* msg, int msgClass, int msgType) +{ + int status = 0; + + switch (msgClass) + { + case Input_Class: + status = event_process_input_class(event, msg, msgType); + break; + + default: + status = -1; + break; + } + + if (status < 0) + printf("Unknown event: class: %d type: %d\n", msgClass, msgType); + + return status; +} + +int event_process_pending_input(rdpInput* input) +{ + int status; + int msgClass; + int msgType; + wMessage message; + wMessageQueue* queue; + + queue = input->queue; + + while (1) + { + status = MessageQueue_Peek(queue, &message, TRUE); + + if (!status) + break; + + if (message.type == WMQ_QUIT) + break; + + msgClass = GetMessageClass(message.type); + msgType = GetMessageType(message.type); + + status = event_process_class(input->event, &message, msgClass, msgType); + } + + return 0; +} + +void event_register_input(rdpEvent* event, rdpInput* input) +{ + /* Input */ + + event->SynchronizeEvent = input->SynchronizeEvent; + event->KeyboardEvent = input->KeyboardEvent; + event->UnicodeKeyboardEvent = input->UnicodeKeyboardEvent; + event->MouseEvent = input->MouseEvent; + event->ExtendedMouseEvent = input->ExtendedMouseEvent; + + input->SynchronizeEvent = event_SynchronizeEvent; + input->KeyboardEvent = event_KeyboardEvent; + input->UnicodeKeyboardEvent = event_UnicodeKeyboardEvent; + input->MouseEvent = event_MouseEvent; + input->ExtendedMouseEvent = event_ExtendedMouseEvent; +} + +rdpEvent* event_new(rdpInput* input) +{ + rdpEvent* event; + + event = (rdpEvent*) malloc(sizeof(rdpEvent)); + + if (event) + { + ZeroMemory(event, sizeof(rdpEvent)); + + event->input = input; + input->queue = MessageQueue_New(); + event_register_input(event, input); + } + + return event; +} + +void event_free(rdpEvent* event) +{ + if (event) + { + MessageQueue_Free(event->input->queue); + free(event); + } +} diff --git a/libfreerdp/core/event.h b/libfreerdp/core/event.h new file mode 100644 index 000000000..e58548c60 --- /dev/null +++ b/libfreerdp/core/event.h @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Asynchronous Event Queue + * + * Copyright 2012 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_CORE_EVENT_PRIVATE_H +#define FREERDP_CORE_EVENT_PRIVATE_H + +#include "message.h" + +#include + +/* Input */ + +#define Input_Class 1 + +#define Input_SynchronizeEvent 1 +#define Input_KeyboardEvent 2 +#define Input_UnicodeKeyboardEvent 3 +#define Input_MouseEvent 4 +#define Input_ExtendedMouseEvent 5 + +/* Event Queue */ + +struct rdp_event +{ + /* Input */ + + pSynchronizeEvent SynchronizeEvent; + pKeyboardEvent KeyboardEvent; + pUnicodeKeyboardEvent UnicodeKeyboardEvent; + pMouseEvent MouseEvent; + pExtendedMouseEvent ExtendedMouseEvent; + + /* Internal */ + + rdpInput* input; +}; + +int event_process_pending_input(rdpInput* input); + +rdpEvent* event_new(rdpInput* input); +void event_free(rdpEvent* event); + +#endif /* FREERDP_CORE_EVENT_PRIVATE_H */ + diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index e979977c2..e35dc8104 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -199,6 +199,21 @@ int freerdp_process_messages(freerdp* instance) return update_process_messages(instance->update); } +HANDLE freerdp_get_input_queue_event_handle(freerdp* instance) +{ + HANDLE event = NULL; + + if (instance->input->queue) + event = MessageQueue_Event(instance->input->queue); + + return event; +} + +int freerdp_process_input(freerdp* instance) +{ + return input_process_events(instance->input); +} + static int freerdp_send_channel_data(freerdp* instance, int channel_id, BYTE* data, int size) { return rdp_send_channel_data(instance->context->rdp, channel_id, data, size); diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index d486069fb..5c9f4e5f6 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -26,6 +26,7 @@ #include #include "input.h" +#include "event.h" void rdp_write_client_input_pdu_header(STREAM* s, UINT16 number) { @@ -368,9 +369,9 @@ BOOL input_recv(rdpInput* input, STREAM* s) void input_register_client_callbacks(rdpInput* input) { - rdpRdp* rdp = input->context->rdp; + rdpSettings* settings = input->context->settings; - if (rdp->settings->FastPathInput) + if (settings->FastPathInput) { input->SynchronizeEvent = input_send_fastpath_synchronize_event; input->KeyboardEvent = input_send_fastpath_keyboard_event; @@ -386,6 +387,13 @@ void input_register_client_callbacks(rdpInput* input) input->MouseEvent = input_send_mouse_event; input->ExtendedMouseEvent = input_send_extended_mouse_event; } + + input->asynchronous = settings->AsyncInput; + + if (input->asynchronous) + { + input->event = event_new(input); + } } void freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags) @@ -421,6 +429,11 @@ void freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT IFCALL(input->ExtendedMouseEvent, input, flags, x, y); } +int input_process_events(rdpInput* input) +{ + return event_process_pending_input(input); +} + rdpInput* input_new(rdpRdp* rdp) { rdpInput* input; @@ -439,6 +452,9 @@ void input_free(rdpInput* input) { if (input != NULL) { + if (input->asynchronous) + event_free(input->event); + free(input); } } diff --git a/libfreerdp/core/input.h b/libfreerdp/core/input.h index 7c749319e..3203367f4 100644 --- a/libfreerdp/core/input.h +++ b/libfreerdp/core/input.h @@ -22,6 +22,7 @@ #include "rdp.h" #include "fastpath.h" +#include "event.h" #include #include @@ -50,6 +51,7 @@ void input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UIN BOOL input_recv(rdpInput* input, STREAM* s); +int input_process_events(rdpInput* input); void input_register_client_callbacks(rdpInput* input); rdpInput* input_new(rdpRdp* rdp); diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index ea3c50241..bf2ccf355 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -1545,7 +1545,7 @@ int message_process_pending_updates(rdpUpdate* update) return 0; } -void message_register_interface(rdpMessage* message, rdpUpdate* update) +void message_register_update(rdpMessage* message, rdpUpdate* update) { rdpPrimaryUpdate* primary; rdpSecondaryUpdate* secondary; @@ -1732,9 +1732,11 @@ rdpMessage* message_new(rdpUpdate* update) if (message) { + ZeroMemory(message, sizeof(rdpMessage)); + message->update = update; update->queue = MessageQueue_New(); - message_register_interface(message, update); + message_register_update(message, update); } return message; diff --git a/libfreerdp/core/message.h b/libfreerdp/core/message.h index 14f428271..2a292a84c 100644 --- a/libfreerdp/core/message.h +++ b/libfreerdp/core/message.h @@ -226,9 +226,8 @@ struct rdp_message }; int message_process_pending_updates(rdpUpdate* update); -void message_register_interface(rdpMessage* message, rdpUpdate* update); -rdpMessage* message_new(); +rdpMessage* message_new(rdpUpdate* update); void message_free(rdpMessage* message); #endif /* FREERDP_CORE_MESSAGE_PRIVATE_H */