22#include <freerdp/config.h>
27#include <winpr/stream.h>
29#include <freerdp/client/channels.h>
30#include <freerdp/client/cliprdr.h>
32#include "android_cliprdr.h"
33#include "android_jni_utils.h"
34#include "android_jni_callback.h"
36static void android_cliprdr_free_formats(
CLIPRDR_FORMAT* formats, UINT32 numFormats)
41 for (UINT32 index = 0; index < numFormats; index++)
42 free(formats[index].formatName);
47UINT android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr)
49 UINT rc = ERROR_INTERNAL_ERROR;
53 const char* formatName;
58 return ERROR_INVALID_PARAMETER;
62 if (!afc || !afc->cliprdr)
63 return ERROR_INVALID_PARAMETER;
66 numFormats = ClipboardGetFormatIds(afc->clipboard, &pFormatIds);
72 for (UINT32 index = 0; index < numFormats; index++)
74 formatId = pFormatIds[index];
75 formatName = ClipboardGetFormatName(afc->clipboard, formatId);
76 formats[index].formatId = formatId;
77 formats[index].formatName =
nullptr;
79 if ((formatId > CF_MAX) && formatName)
81 formats[index].formatName = _strdup(formatName);
83 if (!formats[index].formatName)
88 formatList.common.msgFlags = 0;
89 formatList.numFormats = numFormats;
90 formatList.formats = formats;
91 formatList.common.msgType = CB_FORMAT_LIST;
93 if (!afc->cliprdr->ClientFormatList)
96 rc = afc->cliprdr->ClientFormatList(afc->cliprdr, &formatList);
99 android_cliprdr_free_formats(formats, numFormats);
103static UINT android_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr,
106 UINT rc = ERROR_INVALID_PARAMETER;
115 if (!afc || !afc->clipboardRequestEvent || !cliprdr->ClientFormatDataRequest)
118 formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST;
119 formatDataRequest.common.msgFlags = 0;
120 formatDataRequest.requestedFormatId = formatId;
121 afc->requestedFormatId = formatId;
122 (void)ResetEvent(afc->clipboardRequestEvent);
123 rc = cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest);
128static UINT android_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr)
133 if (!cliprdr || !cliprdr->ClientCapabilities)
134 return ERROR_INVALID_PARAMETER;
136 capabilities.cCapabilitiesSets = 1;
138 generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
139 generalCapabilitySet.capabilitySetLength = 12;
140 generalCapabilitySet.version = CB_CAPS_VERSION_2;
141 generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
142 return cliprdr->ClientCapabilities(cliprdr, &capabilities);
150static UINT android_cliprdr_monitor_ready(CliprdrClientContext* cliprdr,
156 if (!cliprdr || !monitorReady)
157 return ERROR_INVALID_PARAMETER;
162 return ERROR_INVALID_PARAMETER;
164 if ((rc = android_cliprdr_send_client_capabilities(cliprdr)) != CHANNEL_RC_OK)
167 if ((rc = android_cliprdr_send_client_format_list(cliprdr)) != CHANNEL_RC_OK)
170 afc->clipboardSync = TRUE;
171 return CHANNEL_RC_OK;
179static UINT android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr,
185 if (!cliprdr || !capabilities)
186 return ERROR_INVALID_PARAMETER;
191 return ERROR_INVALID_PARAMETER;
193 for (UINT32 index = 0; index < capabilities->cCapabilitiesSets; index++)
195 capabilitySet = &(capabilities->capabilitySets[index]);
197 if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) &&
198 (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN))
202 afc->clipboardCapabilities = generalCapabilitySet->generalFlags;
207 return CHANNEL_RC_OK;
210static UINT android_cliprdr_send_client_format_list_response(CliprdrClientContext* cliprdr,
215 formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE;
216 formatListResponse.common.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
217 formatListResponse.common.dataLen = 0;
219 if (!cliprdr || !cliprdr->ClientFormatListResponse)
220 return ERROR_INVALID_PARAMETER;
222 return cliprdr->ClientFormatListResponse(cliprdr, &formatListResponse);
230static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr,
237 if (!cliprdr || !formatList)
238 return ERROR_INVALID_PARAMETER;
243 return ERROR_INVALID_PARAMETER;
245 android_cliprdr_free_formats(afc->serverFormats, afc->numServerFormats);
246 afc->serverFormats =
nullptr;
247 afc->numServerFormats = 0;
249 if (formatList->numFormats < 1)
250 return android_cliprdr_send_client_format_list_response(cliprdr, TRUE);
252 afc->numServerFormats = formatList->numFormats;
255 if (!afc->serverFormats)
256 return CHANNEL_RC_NO_MEMORY;
258 for (UINT32 index = 0; index < afc->numServerFormats; index++)
260 afc->serverFormats[index].formatId = formatList->formats[index].formatId;
261 afc->serverFormats[index].formatName =
nullptr;
263 if (formatList->formats[index].formatName)
265 afc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName);
267 if (!afc->serverFormats[index].formatName)
268 return CHANNEL_RC_NO_MEMORY;
272 if ((rc = android_cliprdr_send_client_format_list_response(cliprdr, TRUE)) != CHANNEL_RC_OK)
277 for (UINT32 index = 0; index < afc->numServerFormats; index++)
279 format = &(afc->serverFormats[index]);
281 if (format->formatId == CF_UNICODETEXT)
283 if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT)) !=
287 return CHANNEL_RC_OK;
289 else if (format->formatId == CF_TEXT)
291 if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT)) !=
295 return CHANNEL_RC_OK;
300 for (UINT32 index = 0; index < afc->numServerFormats; index++)
302 format = &(afc->serverFormats[index]);
304 if (format->formatId == CF_DIB || format->formatId == CF_DIBV5)
306 if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, format->formatId)) !=
314 return CHANNEL_RC_OK;
323android_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr,
326 if (!cliprdr || !formatListResponse)
327 return ERROR_INVALID_PARAMETER;
329 return CHANNEL_RC_OK;
338android_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr,
341 if (!cliprdr || !lockClipboardData)
342 return ERROR_INVALID_PARAMETER;
344 return CHANNEL_RC_OK;
352static UINT android_cliprdr_server_unlock_clipboard_data(
355 if (!cliprdr || !unlockClipboardData)
356 return ERROR_INVALID_PARAMETER;
358 return CHANNEL_RC_OK;
367android_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr,
377 if (!cliprdr || !formatDataRequest || !cliprdr->ClientFormatDataResponse)
378 return ERROR_INVALID_PARAMETER;
383 return ERROR_INVALID_PARAMETER;
385 formatId = formatDataRequest->requestedFormatId;
386 data = (BYTE*)ClipboardGetData(afc->clipboard, formatId, &size);
387 response.common.msgFlags = CB_RESPONSE_OK;
388 response.common.dataLen = size;
389 response.requestedFormatData = data;
393 response.common.msgFlags = CB_RESPONSE_FAIL;
394 response.common.dataLen = 0;
395 response.requestedFormatData =
nullptr;
398 rc = cliprdr->ClientFormatDataResponse(cliprdr, &response);
409android_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr,
414 if (!cliprdr || !formatDataResponse)
415 return ERROR_INVALID_PARAMETER;
420 return ERROR_INVALID_PARAMETER;
422 freerdp* instance = ((rdpContext*)afc)->instance;
425 return ERROR_INVALID_PARAMETER;
427 for (UINT32 index = 0; index < afc->numServerFormats; index++)
429 if (afc->requestedFormatId == afc->serverFormats[index].formatId)
430 format = &(afc->serverFormats[index]);
435 (void)SetEvent(afc->clipboardRequestEvent);
436 return ERROR_INTERNAL_ERROR;
439 UINT32 formatId = format->formatId;
440 if (format->formatName)
441 formatId = ClipboardRegisterFormat(afc->clipboard, format->formatName);
443 uint32_t size = formatDataResponse->common.dataLen;
445 if (!ClipboardSetData(afc->clipboard, formatId, formatDataResponse->requestedFormatData, size))
446 return ERROR_INTERNAL_ERROR;
448 (void)SetEvent(afc->clipboardRequestEvent);
455 JNIEnv* env =
nullptr;
456 UINT32 plainFormatId = ClipboardRegisterFormat(afc->clipboard,
"text/plain");
457 char* data = (
char*)ClipboardGetData(afc->clipboard, plainFormatId, &size);
460 jboolean attached = jni_attach_thread(&env);
461 size = strnlen(data, size);
462 jstring jdata = jniNewStringUTF(env, data, size);
463 freerdp_callback(
"OnRemoteClipboardChanged",
"(JLjava/lang/String;)V", (jlong)instance,
465 (*env)->DeleteLocalRef(env, jdata);
468 if (attached == JNI_TRUE)
475 UINT32 pngFormatId = ClipboardRegisterFormat(afc->clipboard,
"image/png");
476 BYTE* pngData = (BYTE*)ClipboardGetData(afc->clipboard, pngFormatId, &size);
480 JNIEnv* env =
nullptr;
481 jboolean attached = jni_attach_thread(&env);
482 jbyteArray jpngData = (*env)->NewByteArray(env, (jsize)size);
486 (*env)->SetByteArrayRegion(env, jpngData, 0, (jsize)size,
487 (
const jbyte*)pngData);
488 freerdp_callback(
"OnRemoteClipboardImageChanged",
"(J[B)V", (jlong)instance,
490 (*env)->DeleteLocalRef(env, jpngData);
495 if (attached == JNI_TRUE)
504 return CHANNEL_RC_OK;
512static UINT android_cliprdr_server_file_contents_request(
515 if (!cliprdr || !fileContentsRequest)
516 return ERROR_INVALID_PARAMETER;
518 return CHANNEL_RC_OK;
526static UINT android_cliprdr_server_file_contents_response(
529 if (!cliprdr || !fileContentsResponse)
530 return ERROR_INVALID_PARAMETER;
532 return CHANNEL_RC_OK;
535BOOL android_cliprdr_init(
androidContext* afc, CliprdrClientContext* cliprdr)
537 wClipboard* clipboard;
540 if (!afc || !cliprdr)
543 if (!(hevent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
546 if (!(clipboard = ClipboardCreate()))
548 (void)CloseHandle(hevent);
552 afc->cliprdr = cliprdr;
553 afc->clipboard = clipboard;
554 afc->clipboardRequestEvent = hevent;
555 cliprdr->custom = (
void*)afc;
556 cliprdr->MonitorReady = android_cliprdr_monitor_ready;
557 cliprdr->ServerCapabilities = android_cliprdr_server_capabilities;
558 cliprdr->ServerFormatList = android_cliprdr_server_format_list;
559 cliprdr->ServerFormatListResponse = android_cliprdr_server_format_list_response;
560 cliprdr->ServerLockClipboardData = android_cliprdr_server_lock_clipboard_data;
561 cliprdr->ServerUnlockClipboardData = android_cliprdr_server_unlock_clipboard_data;
562 cliprdr->ServerFormatDataRequest = android_cliprdr_server_format_data_request;
563 cliprdr->ServerFormatDataResponse = android_cliprdr_server_format_data_response;
564 cliprdr->ServerFileContentsRequest = android_cliprdr_server_file_contents_request;
565 cliprdr->ServerFileContentsResponse = android_cliprdr_server_file_contents_response;
569BOOL android_cliprdr_uninit(
androidContext* afc, CliprdrClientContext* cliprdr)
571 if (!afc || !cliprdr)
574 cliprdr->custom =
nullptr;
575 afc->cliprdr =
nullptr;
576 ClipboardDestroy(afc->clipboard);
577 (void)CloseHandle(afc->clipboardRequestEvent);