void remmina_rdp_cliprdr_send_client_format_list(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); RemminaPluginRdpUiObject* ui; rfContext* rfi = GET_PLUGIN_DATA(gp); rfClipboard* clipboard; CLIPRDR_FORMAT_LIST *pFormatList; RemminaPluginRdpEvent rdp_event = { 0 }; if (!rfi || !rfi->connected || rfi->is_reconnecting) return; clipboard = &(rfi->clipboard); ui = g_new0(RemminaPluginRdpUiObject, 1); ui->type = REMMINA_RDP_UI_CLIPBOARD; ui->clipboard.clipboard = clipboard; ui->clipboard.type = REMMINA_RDP_UI_CLIPBOARD_FORMATLIST; pFormatList = remmina_rdp_event_queue_ui_sync_retptr(gp, ui); rdp_event.type = REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_LIST; rdp_event.clipboard_formatlist.pFormatList = pFormatList; remmina_rdp_event_event_push(gp, &rdp_event); }
static gboolean remmina_rdp_event_on_clipboard(GtkClipboard *clipboard, GdkEvent *event, RemminaProtocolWidget *gp) { RemminaPluginRdpEvent rdp_event = { 0 }; rdp_event.type = REMMINA_RDP_EVENT_TYPE_CLIPBOARD; remmina_rdp_event_event_push(gp, &rdp_event); return TRUE; }
static gboolean remmina_rdp_event_on_motion(GtkWidget* widget, GdkEventMotion* event, RemminaProtocolWidget* gp) { RemminaPluginRdpEvent rdp_event = { 0 }; rdp_event.type = REMMINA_RDP_EVENT_TYPE_MOUSE; rdp_event.mouse_event.flags = PTR_FLAGS_MOVE; remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y); remmina_rdp_event_event_push(gp, &rdp_event); return TRUE; }
static gboolean remmina_rdp_event_on_button(GtkWidget* widget, GdkEventButton* event, RemminaProtocolWidget* gp) { gint flag; RemminaPluginRdpEvent rdp_event = { 0 }; /* We only accept 3 buttons */ if ((event->button < 1) || (event->button > 3)) return FALSE; /* We bypass 2button-press and 3button-press events */ if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE)) return TRUE; rdp_event.type = REMMINA_RDP_EVENT_TYPE_MOUSE; remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y); flag = 0; if (event->type == GDK_BUTTON_PRESS) flag = PTR_FLAGS_DOWN; switch (event->button) { case 1: flag |= PTR_FLAGS_BUTTON1; break; case 2: flag |= PTR_FLAGS_BUTTON3; break; case 3: flag |= PTR_FLAGS_BUTTON2; break; } if (flag != 0) { rdp_event.mouse_event.flags = flag; remmina_rdp_event_event_push(gp, &rdp_event); } return TRUE; }
static gboolean remmina_rdp_event_on_scroll(GtkWidget* widget, GdkEventScroll* event, RemminaProtocolWidget* gp) { gint flag; RemminaPluginRdpEvent rdp_event = { 0 }; flag = 0; rdp_event.type = REMMINA_RDP_EVENT_TYPE_MOUSE; switch (event->direction) { case GDK_SCROLL_UP: flag = PTR_FLAGS_WHEEL | 0x0078; break; case GDK_SCROLL_DOWN: flag = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; break; #ifdef GDK_SCROLL_SMOOTH case GDK_SCROLL_SMOOTH: if (event->delta_y < 0) flag = PTR_FLAGS_WHEEL | 0x0078; if (event->delta_y > 0) flag = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; if (!flag) return FALSE; break; #endif default: return FALSE; } rdp_event.mouse_event.flags = flag; remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y); remmina_rdp_event_event_push(gp, &rdp_event); return TRUE; }
static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, gint scancode) { gint i, k; rfContext* rfi; RemminaPluginRdpEvent rdp_event = { 0 }; rfi = GET_DATA(gp); rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE; if (scancode == 0) { /* Send all release key events for previously pressed keys */ rdp_event.key_event.up = True; for (i = 0; i < rfi->pressed_keys->len; i++) { rdp_event.key_event.key_code = g_array_index(rfi->pressed_keys, gint, i); remmina_rdp_event_event_push(gp, &rdp_event); } g_array_set_size(rfi->pressed_keys, 0); } else { /* Unregister the keycode only */ for (i = 0; i < rfi->pressed_keys->len; i++) { k = g_array_index(rfi->pressed_keys, gint, i); if (k == scancode) { g_array_remove_index_fast(rfi->pressed_keys, i); break; } } } }
static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp) { GdkDisplay* display; guint16 cooked_keycode; rfContext* rfi; RemminaPluginRdpEvent rdp_event; rfi = GET_DATA(gp); rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE; rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? False : True); rdp_event.key_event.extended = False; switch (event->keyval) { case GDK_KEY_Pause: rdp_event.key_event.key_code = 0x1D; rdp_event.key_event.up = False; remmina_rdp_event_event_push(gp, &rdp_event); rdp_event.key_event.key_code = 0x45; rdp_event.key_event.up = False; remmina_rdp_event_event_push(gp, &rdp_event); rdp_event.key_event.key_code = 0x1D; rdp_event.key_event.up = True; remmina_rdp_event_event_push(gp, &rdp_event); rdp_event.key_event.key_code = 0x45; rdp_event.key_event.up = True; remmina_rdp_event_event_push(gp, &rdp_event); break; default: if (!rfi->use_client_keymap) { rdp_event.key_event.key_code = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode); remmina_plugin_service->log_printf("[RDP]keyval=%04X keycode=%i scancode=%i extended=%i\n", event->keyval, event->hardware_keycode, rdp_event.key_event.key_code, &rdp_event.key_event.extended); } else { //TODO: Port to GDK functions display = gdk_display_get_default(); cooked_keycode = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XKeycodeToKeysym(GDK_DISPLAY_XDISPLAY(display), event->hardware_keycode, 0)); rdp_event.key_event.key_code = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(cooked_keycode); remmina_plugin_service->log_printf("[RDP]keyval=%04X raw_keycode=%i cooked_keycode=%i scancode=%i extended=%i\n", event->keyval, event->hardware_keycode, cooked_keycode, rdp_event.key_event.key_code, &rdp_event.key_event.extended); } if (rdp_event.key_event.key_code) remmina_rdp_event_event_push(gp, &rdp_event); break; } /* Register/unregister the pressed key */ if (rdp_event.key_event.key_code) { if (event->type == GDK_KEY_PRESS) g_array_append_val(rfi->pressed_keys, rdp_event.key_event.key_code); else remmina_rdp_event_release_key(gp, rdp_event.key_event.key_code); } return TRUE; }
void remmina_rdp_cliprdr_get_clipboard_data(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) { TRACE_CALL(__func__); GtkClipboard* gtkClipboard; UINT8* inbuf = NULL; UINT8* outbuf = NULL; GdkPixbuf *image = NULL; int size = 0; rfContext* rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event = { 0 }; CLIPRDR_FORMAT_DATA_RESPONSE* pFormatDataResponse; gtkClipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD); if (gtkClipboard) { switch (ui->clipboard.format) { case CF_TEXT: case CF_UNICODETEXT: case CB_FORMAT_HTML: { inbuf = (UINT8*)gtk_clipboard_wait_for_text(gtkClipboard); break; } case CB_FORMAT_PNG: case CB_FORMAT_JPEG: case CF_DIB: case CF_DIBV5: { image = gtk_clipboard_wait_for_image(gtkClipboard); break; } } } /* No data received, send nothing */ if (inbuf != NULL || image != NULL) { switch (ui->clipboard.format) { case CF_TEXT: case CB_FORMAT_HTML: { size = strlen((char*)inbuf); outbuf = lf2crlf(inbuf, &size); break; } case CF_UNICODETEXT: { size = strlen((char*)inbuf); inbuf = lf2crlf(inbuf, &size); size = (ConvertToUnicode(CP_UTF8, 0, (CHAR*)inbuf, -1, (WCHAR**)&outbuf, 0) ) * sizeof(WCHAR); g_free(inbuf); break; } case CB_FORMAT_PNG: { gchar* data; gsize buffersize; gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "png", NULL, NULL); outbuf = (UINT8*)malloc(buffersize); memcpy(outbuf, data, buffersize); size = buffersize; g_object_unref(image); break; } case CB_FORMAT_JPEG: { gchar* data; gsize buffersize; gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "jpeg", NULL, NULL); outbuf = (UINT8*)malloc(buffersize); memcpy(outbuf, data, buffersize); size = buffersize; g_object_unref(image); break; } case CF_DIB: case CF_DIBV5: { gchar* data; gsize buffersize; gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "bmp", NULL, NULL); size = buffersize - 14; outbuf = (UINT8*)malloc(size); memcpy(outbuf, data + 14, size); g_object_unref(image); break; } } } pFormatDataResponse = (CLIPRDR_FORMAT_DATA_RESPONSE*)malloc(sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); if (!pFormatDataResponse) { if (outbuf) free(outbuf); return; } ZeroMemory(pFormatDataResponse, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); rdp_event.type = REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_DATA_RESPONSE; rdp_event.clipboard_formatdataresponse.pFormatDataResponse = pFormatDataResponse; pFormatDataResponse->msgFlags = CB_RESPONSE_OK; pFormatDataResponse->dataLen = size; pFormatDataResponse->requestedFormatData = outbuf; remmina_rdp_event_event_push(gp, &rdp_event); }
void remmina_rdp_cliprdr_request_data(GtkClipboard *gtkClipboard, GtkSelectionData *selection_data, guint info, RemminaProtocolWidget* gp ) { TRACE_CALL(__func__); /* Called by GTK when someone press "Paste" on the client side. * We ask to the server the data we need */ CLIPRDR_FORMAT_DATA_REQUEST* pFormatDataRequest; rfClipboard* clipboard; rfContext* rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event = { 0 }; struct timespec to; struct timeval tv; int rc; clipboard = &(rfi->clipboard); if ( clipboard->srv_clip_data_wait != SCDW_NONE ) { remmina_plugin_service->log_printf("[RDP] Cannot paste now, I’m transferring clipboard data from server. Try again later\n"); return; } clipboard->format = info; /* Request Clipboard content from the server, the request is async */ pthread_mutex_lock(&clipboard->transfer_clip_mutex); pFormatDataRequest = (CLIPRDR_FORMAT_DATA_REQUEST*)malloc(sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); ZeroMemory(pFormatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); pFormatDataRequest->requestedFormatId = clipboard->format; clipboard->srv_clip_data_wait = SCDW_BUSY_WAIT; rdp_event.type = REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_DATA_REQUEST; rdp_event.clipboard_formatdatarequest.pFormatDataRequest = pFormatDataRequest; remmina_rdp_event_event_push(gp, &rdp_event); /* Busy wait clibpoard data for CLIPBOARD_TRANSFER_WAIT_TIME seconds */ gettimeofday(&tv, NULL); to.tv_sec = tv.tv_sec + CLIPBOARD_TRANSFER_WAIT_TIME; to.tv_nsec = tv.tv_usec * 1000; rc = pthread_cond_timedwait(&clipboard->transfer_clip_cond, &clipboard->transfer_clip_mutex, &to); if ( rc == 0 ) { /* Data has arrived without timeout */ if (clipboard->srv_data != NULL) { if (info == CB_FORMAT_PNG || info == CF_DIB || info == CF_DIBV5 || info == CB_FORMAT_JPEG) { gtk_selection_data_set_pixbuf(selection_data, clipboard->srv_data); g_object_unref(clipboard->srv_data); }else { gtk_selection_data_set_text(selection_data, clipboard->srv_data, -1); free(clipboard->srv_data); } } clipboard->srv_clip_data_wait = SCDW_NONE; } else { clipboard->srv_clip_data_wait = SCDW_ASYNCWAIT; if ( rc == ETIMEDOUT ) { remmina_plugin_service->log_printf("[RDP] Clipboard data has not been transferred from the server in %d seconds. Try to paste later.\n", CLIPBOARD_TRANSFER_WAIT_TIME); }else { remmina_plugin_service->log_printf("[RDP] internal error: pthread_cond_timedwait() returned %d\n", rc); clipboard->srv_clip_data_wait = SCDW_NONE; } } pthread_mutex_unlock(&clipboard->transfer_clip_mutex); }