FreeRDP
Loading...
Searching...
No Matches
android_event.c
1
13#include <freerdp/config.h>
14
15#include <winpr/crt.h>
16
17#include <freerdp/freerdp.h>
18#include <freerdp/log.h>
19
20#define TAG CLIENT_TAG("android")
21
22#include "android_freerdp.h"
23#include "android_cliprdr.h"
24
25BOOL android_push_event(freerdp* inst, ANDROID_EVENT* event)
26{
27 androidContext* aCtx = (androidContext*)inst->context;
28
29 if (aCtx->event_queue->count >= aCtx->event_queue->size)
30 {
31 size_t new_size = aCtx->event_queue->size;
32 do
33 {
34 if (new_size >= SIZE_MAX - 128ull)
35 return FALSE;
36
37 new_size += 128ull;
38 } while (new_size <= aCtx->event_queue->count);
39 void* new_events =
40 realloc((void*)aCtx->event_queue->events, sizeof(ANDROID_EVENT*) * new_size);
41
42 if (!new_events)
43 return FALSE;
44
45 aCtx->event_queue->events = new_events;
46 aCtx->event_queue->size = new_size;
47 }
48
49 aCtx->event_queue->events[(aCtx->event_queue->count)++] = event;
50 return SetEvent(aCtx->event_queue->isSet);
51}
52
53static ANDROID_EVENT* android_peek_event(ANDROID_EVENT_QUEUE* queue)
54{
55 ANDROID_EVENT* event;
56
57 if (queue->count < 1)
58 return nullptr;
59
60 event = queue->events[0];
61 return event;
62}
63
64static ANDROID_EVENT* android_pop_event(ANDROID_EVENT_QUEUE* queue)
65{
66 ANDROID_EVENT* event;
67
68 if (queue->count < 1)
69 return nullptr;
70
71 event = queue->events[0];
72 (queue->count)--;
73
74 for (size_t i = 0; i < queue->count; i++)
75 {
76 queue->events[i] = queue->events[i + 1];
77 }
78
79 return event;
80}
81
82static BOOL android_process_event(ANDROID_EVENT_QUEUE* queue, freerdp* inst)
83{
84 rdpContext* context;
85
86 WINPR_ASSERT(queue);
87 WINPR_ASSERT(inst);
88
89 context = inst->context;
90 WINPR_ASSERT(context);
91
92 while (android_peek_event(queue))
93 {
94 BOOL rc = FALSE;
95 androidContext* afc = (androidContext*)context;
96 ANDROID_EVENT* event = android_pop_event(queue);
97
98 WINPR_ASSERT(event);
99
100 switch (event->type)
101 {
102 case EVENT_TYPE_KEY:
103 {
104 ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*)event;
105
106 rc = freerdp_input_send_keyboard_event(context->input, key_event->flags,
107 key_event->scancode);
108 }
109 break;
110
111 case EVENT_TYPE_KEY_UNICODE:
112 {
113 ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*)event;
114
115 rc = freerdp_input_send_unicode_keyboard_event(context->input, key_event->flags,
116 key_event->scancode);
117 }
118 break;
119
120 case EVENT_TYPE_CURSOR:
121 {
122 ANDROID_EVENT_CURSOR* cursor_event = (ANDROID_EVENT_CURSOR*)event;
123
124 rc = freerdp_input_send_mouse_event(context->input, cursor_event->flags,
125 cursor_event->x, cursor_event->y);
126 }
127 break;
128
129 case EVENT_TYPE_CLIPBOARD:
130 {
131 ANDROID_EVENT_CLIPBOARD* clipboard_event = (ANDROID_EVENT_CLIPBOARD*)event;
132 const char* mimeType = clipboard_event->mimeType;
133 UINT32 formatId = ClipboardRegisterFormat(afc->clipboard, mimeType);
134 UINT32 size = clipboard_event->data_length;
135
136 if (size)
137 ClipboardSetData(afc->clipboard, formatId, clipboard_event->data, size);
138 else
139 ClipboardEmpty(afc->clipboard);
140
141 rc = (android_cliprdr_send_client_format_list(afc->cliprdr) == CHANNEL_RC_OK);
142 }
143 break;
144
145 case EVENT_TYPE_DISCONNECT:
146 default:
147 break;
148 }
149
150 android_event_free(event);
151
152 if (!rc)
153 return FALSE;
154 }
155
156 return TRUE;
157}
158
159HANDLE android_get_handle(freerdp* inst)
160{
161 androidContext* aCtx;
162
163 if (!inst || !inst->context)
164 return nullptr;
165
166 aCtx = (androidContext*)inst->context;
167
168 if (!aCtx->event_queue || !aCtx->event_queue->isSet)
169 return nullptr;
170
171 return aCtx->event_queue->isSet;
172}
173
174BOOL android_check_handle(freerdp* inst)
175{
176 androidContext* aCtx;
177
178 if (!inst || !inst->context)
179 return FALSE;
180
181 aCtx = (androidContext*)inst->context;
182
183 if (!aCtx->event_queue || !aCtx->event_queue->isSet)
184 return FALSE;
185
186 if (WaitForSingleObject(aCtx->event_queue->isSet, 0) == WAIT_OBJECT_0)
187 {
188 if (!ResetEvent(aCtx->event_queue->isSet))
189 return FALSE;
190
191 if (!android_process_event(aCtx->event_queue, inst))
192 return FALSE;
193 }
194
195 return TRUE;
196}
197
198ANDROID_EVENT_KEY* android_event_key_new(int flags, UINT16 scancode)
199{
200 ANDROID_EVENT_KEY* event = (ANDROID_EVENT_KEY*)calloc(1, sizeof(ANDROID_EVENT_KEY));
201
202 if (!event)
203 return nullptr;
204
205 event->type = EVENT_TYPE_KEY;
206 event->flags = flags;
207 event->scancode = scancode;
208 return event;
209}
210
211static void android_event_key_free(ANDROID_EVENT_KEY* event)
212{
213 free(event);
214}
215
216ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 flags, UINT16 key)
217{
218 ANDROID_EVENT_KEY* event;
219 event = (ANDROID_EVENT_KEY*)calloc(1, sizeof(ANDROID_EVENT_KEY));
220
221 if (!event)
222 return nullptr;
223
224 event->type = EVENT_TYPE_KEY_UNICODE;
225 event->flags = flags;
226 event->scancode = key;
227 return event;
228}
229
230static void android_event_unicodekey_free(ANDROID_EVENT_KEY* event)
231{
232 free(event);
233}
234
235ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, UINT16 x, UINT16 y)
236{
238 event = (ANDROID_EVENT_CURSOR*)calloc(1, sizeof(ANDROID_EVENT_CURSOR));
239
240 if (!event)
241 return nullptr;
242
243 event->type = EVENT_TYPE_CURSOR;
244 event->x = x;
245 event->y = y;
246 event->flags = flags;
247 return event;
248}
249
250static void android_event_cursor_free(ANDROID_EVENT_CURSOR* event)
251{
252 free(event);
253}
254
255ANDROID_EVENT* android_event_disconnect_new(void)
256{
257 ANDROID_EVENT* event;
258 event = (ANDROID_EVENT*)calloc(1, sizeof(ANDROID_EVENT));
259
260 if (!event)
261 return nullptr;
262
263 event->type = EVENT_TYPE_DISCONNECT;
264 return event;
265}
266
267static void android_event_disconnect_free(ANDROID_EVENT* event)
268{
269 free(event);
270}
271
272ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(const void* data, size_t data_length,
273 const char* mimeType)
274{
276 event = (ANDROID_EVENT_CLIPBOARD*)calloc(1, sizeof(ANDROID_EVENT_CLIPBOARD));
277
278 if (!event)
279 return nullptr;
280
281 event->type = EVENT_TYPE_CLIPBOARD;
282 event->mimeType = mimeType ? _strdup(mimeType) : nullptr;
283
284 if (mimeType && !event->mimeType)
285 {
286 free(event);
287 return nullptr;
288 }
289
290 if (data && data_length > 0)
291 {
292 const BOOL isText = !mimeType || strcmp(mimeType, "text/plain") == 0;
293 /* Text data needs a null terminator; image data is stored as-is. */
294 event->data = isText ? calloc(data_length + 1, sizeof(char)) : malloc(data_length);
295
296 if (!event->data)
297 {
298 free(event->mimeType);
299 free(event);
300 return nullptr;
301 }
302
303 memcpy(event->data, data, data_length);
304 event->data_length = isText ? data_length + 1 : data_length;
305 }
306
307 return event;
308}
309
310static void android_event_clipboard_free(ANDROID_EVENT_CLIPBOARD* event)
311{
312 if (event)
313 {
314 free(event->data);
315 free(event->mimeType);
316 free(event);
317 }
318}
319
320BOOL android_event_queue_init(freerdp* inst)
321{
322 androidContext* aCtx = (androidContext*)inst->context;
323 ANDROID_EVENT_QUEUE* queue;
324 queue = (ANDROID_EVENT_QUEUE*)calloc(1, sizeof(ANDROID_EVENT_QUEUE));
325
326 if (!queue)
327 {
328 WLog_ERR(TAG, "android_event_queue_init: memory allocation failed");
329 return FALSE;
330 }
331
332 queue->size = 16;
333 queue->count = 0;
334 queue->isSet = CreateEventA(nullptr, TRUE, FALSE, nullptr);
335
336 if (!queue->isSet)
337 {
338 free(queue);
339 return FALSE;
340 }
341
342 queue->events = (ANDROID_EVENT**)calloc(queue->size, sizeof(ANDROID_EVENT*));
343
344 if (!queue->events)
345 {
346 WLog_ERR(TAG, "android_event_queue_init: memory allocation failed");
347 (void)CloseHandle(queue->isSet);
348 free(queue);
349 return FALSE;
350 }
351
352 aCtx->event_queue = queue;
353 return TRUE;
354}
355
356void android_event_queue_uninit(freerdp* inst)
357{
358 androidContext* aCtx;
359 ANDROID_EVENT_QUEUE* queue;
360
361 if (!inst || !inst->context)
362 return;
363
364 aCtx = (androidContext*)inst->context;
365 queue = aCtx->event_queue;
366
367 if (queue)
368 {
369 if (queue->isSet)
370 {
371 (void)CloseHandle(queue->isSet);
372 queue->isSet = nullptr;
373 }
374
375 if (queue->events)
376 {
377 free(queue->events);
378 queue->events = nullptr;
379 queue->size = 0;
380 queue->count = 0;
381 }
382
383 free(queue);
384 }
385}
386
387void android_event_free(ANDROID_EVENT* event)
388{
389 if (!event)
390 return;
391
392 switch (event->type)
393 {
394 case EVENT_TYPE_KEY:
395 android_event_key_free((ANDROID_EVENT_KEY*)event);
396 break;
397
398 case EVENT_TYPE_KEY_UNICODE:
399 android_event_unicodekey_free((ANDROID_EVENT_KEY*)event);
400 break;
401
402 case EVENT_TYPE_CURSOR:
403 android_event_cursor_free((ANDROID_EVENT_CURSOR*)event);
404 break;
405
406 case EVENT_TYPE_DISCONNECT:
407 android_event_disconnect_free((ANDROID_EVENT*)event);
408 break;
409
410 case EVENT_TYPE_CLIPBOARD:
411 android_event_clipboard_free((ANDROID_EVENT_CLIPBOARD*)event);
412 break;
413
414 default:
415 break;
416 }
417}