/** * FreeRDP: A Remote Desktop Protocol Implementation * Android Event System * * Copyright 2010-2012 Marc-Andre Moreau * Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #define TAG CLIENT_TAG("android") #ifdef HAVE_UNISTD_H #include #endif #include "android_freerdp.h" #include "android_cliprdr.h" BOOL android_push_event(freerdp* inst, ANDROID_EVENT* event) { androidContext* aCtx = (androidContext*)inst->context; if (aCtx->event_queue->count >= aCtx->event_queue->size) { int new_size; void* new_events; new_size = aCtx->event_queue->size * 2; new_events = realloc((void*)aCtx->event_queue->events, sizeof(ANDROID_EVENT*) * new_size); if (!new_events) return FALSE; aCtx->event_queue->events = new_events; aCtx->event_queue->size = new_size; } aCtx->event_queue->events[(aCtx->event_queue->count)++] = event; return SetEvent(aCtx->event_queue->isSet); } static ANDROID_EVENT* android_peek_event(ANDROID_EVENT_QUEUE* queue) { ANDROID_EVENT* event; if (queue->count < 1) return NULL; event = queue->events[0]; return event; } static ANDROID_EVENT* android_pop_event(ANDROID_EVENT_QUEUE* queue) { int i; ANDROID_EVENT* event; if (queue->count < 1) return NULL; event = queue->events[0]; (queue->count)--; for (i = 0; i < queue->count; i++) { queue->events[i] = queue->events[i + 1]; } return event; } static BOOL android_process_event(ANDROID_EVENT_QUEUE* queue, freerdp* inst) { ANDROID_EVENT* event; rdpContext* context = inst->context; androidContext* afc = (androidContext*)context; while (android_peek_event(queue)) { event = android_pop_event(queue); if (event->type == EVENT_TYPE_KEY) { ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*)event; inst->input->KeyboardEvent(inst->input, key_event->flags, key_event->scancode); android_event_free((ANDROID_EVENT*)key_event); } else if (event->type == EVENT_TYPE_KEY_UNICODE) { ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*)event; inst->input->UnicodeKeyboardEvent(inst->input, key_event->flags, key_event->scancode); android_event_free((ANDROID_EVENT*)key_event); } else if (event->type == EVENT_TYPE_CURSOR) { ANDROID_EVENT_CURSOR* cursor_event = (ANDROID_EVENT_CURSOR*)event; inst->input->MouseEvent(inst->input, cursor_event->flags, cursor_event->x, cursor_event->y); android_event_free((ANDROID_EVENT*)cursor_event); } else if (event->type == EVENT_TYPE_CLIPBOARD) { UINT32 size; UINT32 formatId; ANDROID_EVENT_CLIPBOARD* clipboard_event = (ANDROID_EVENT_CLIPBOARD*)event; formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING"); size = clipboard_event->data_length; if (size) ClipboardSetData(afc->clipboard, formatId, clipboard_event->data, size); else ClipboardEmpty(afc->clipboard); android_cliprdr_send_client_format_list(afc->cliprdr); android_event_free((ANDROID_EVENT*)clipboard_event); } else if (event->type == EVENT_TYPE_DISCONNECT) { android_event_free(event); return FALSE; } } return TRUE; } HANDLE android_get_handle(freerdp* inst) { androidContext* aCtx; if (!inst || !inst->context) return NULL; aCtx = (androidContext*)inst->context; if (!aCtx->event_queue || !aCtx->event_queue->isSet) return NULL; return aCtx->event_queue->isSet; } BOOL android_check_handle(freerdp* inst) { androidContext* aCtx; if (!inst || !inst->context) return FALSE; aCtx = (androidContext*)inst->context; if (!aCtx->event_queue || !aCtx->event_queue->isSet) return FALSE; if (WaitForSingleObject(aCtx->event_queue->isSet, 0) == WAIT_OBJECT_0) { if (!ResetEvent(aCtx->event_queue->isSet)) return FALSE; if (!android_process_event(aCtx->event_queue, inst)) return FALSE; } return TRUE; } ANDROID_EVENT_KEY* android_event_key_new(int flags, UINT16 scancode) { ANDROID_EVENT_KEY* event; event = (ANDROID_EVENT_KEY*)calloc(1, sizeof(ANDROID_EVENT_KEY)); if (!event) return NULL; event->type = EVENT_TYPE_KEY; event->flags = flags; event->scancode = scancode; return event; } static void android_event_key_free(ANDROID_EVENT_KEY* event) { free(event); } ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 flags, UINT16 key) { ANDROID_EVENT_KEY* event; event = (ANDROID_EVENT_KEY*)calloc(1, sizeof(ANDROID_EVENT_KEY)); if (!event) return NULL; event->type = EVENT_TYPE_KEY_UNICODE; event->flags = flags; event->scancode = key; return event; } static void android_event_unicodekey_free(ANDROID_EVENT_KEY* event) { free(event); } ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, UINT16 x, UINT16 y) { ANDROID_EVENT_CURSOR* event; event = (ANDROID_EVENT_CURSOR*)calloc(1, sizeof(ANDROID_EVENT_CURSOR)); if (!event) return NULL; event->type = EVENT_TYPE_CURSOR; event->x = x; event->y = y; event->flags = flags; return event; } static void android_event_cursor_free(ANDROID_EVENT_CURSOR* event) { free(event); } ANDROID_EVENT* android_event_disconnect_new(void) { ANDROID_EVENT* event; event = (ANDROID_EVENT*)calloc(1, sizeof(ANDROID_EVENT)); if (!event) return NULL; event->type = EVENT_TYPE_DISCONNECT; return event; } static void android_event_disconnect_free(ANDROID_EVENT* event) { free(event); } ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(const void* data, size_t data_length) { ANDROID_EVENT_CLIPBOARD* event; event = (ANDROID_EVENT_CLIPBOARD*)calloc(1, sizeof(ANDROID_EVENT_CLIPBOARD)); if (!event) return NULL; event->type = EVENT_TYPE_CLIPBOARD; if (data) { event->data = calloc(data_length + 1, sizeof(char)); if (!event->data) { free(event); return NULL; } memcpy(event->data, data, data_length); event->data_length = data_length + 1; } return event; } static void android_event_clipboard_free(ANDROID_EVENT_CLIPBOARD* event) { if (event) { free(event->data); free(event); } } BOOL android_event_queue_init(freerdp* inst) { androidContext* aCtx = (androidContext*)inst->context; ANDROID_EVENT_QUEUE* queue; queue = (ANDROID_EVENT_QUEUE*)calloc(1, sizeof(ANDROID_EVENT_QUEUE)); if (!queue) { WLog_ERR(TAG, "android_event_queue_init: memory allocation failed"); return FALSE; } queue->size = 16; queue->count = 0; queue->isSet = CreateEventA(NULL, TRUE, FALSE, NULL); if (!queue->isSet) { free(queue); return FALSE; } queue->events = (ANDROID_EVENT**)calloc(queue->size, sizeof(ANDROID_EVENT*)); if (!queue->events) { WLog_ERR(TAG, "android_event_queue_init: memory allocation failed"); CloseHandle(queue->isSet); free(queue); return FALSE; } aCtx->event_queue = queue; return TRUE; } void android_event_queue_uninit(freerdp* inst) { androidContext* aCtx; ANDROID_EVENT_QUEUE* queue; if (!inst || !inst->context) return; aCtx = (androidContext*)inst->context; queue = aCtx->event_queue; if (queue) { if (queue->isSet) { CloseHandle(queue->isSet); queue->isSet = NULL; } if (queue->events) { free(queue->events); queue->events = NULL; queue->size = 0; queue->count = 0; } free(queue); } } void android_event_free(ANDROID_EVENT* event) { if (!event) return; switch (event->type) { case EVENT_TYPE_KEY: android_event_key_free((ANDROID_EVENT_KEY*)event); break; case EVENT_TYPE_KEY_UNICODE: android_event_unicodekey_free((ANDROID_EVENT_KEY*)event); break; case EVENT_TYPE_CURSOR: android_event_cursor_free((ANDROID_EVENT_CURSOR*)event); break; case EVENT_TYPE_DISCONNECT: android_event_disconnect_free((ANDROID_EVENT*)event); break; case EVENT_TYPE_CLIPBOARD: android_event_clipboard_free((ANDROID_EVENT_CLIPBOARD*)event); break; default: break; } }