diff options
author | Giovanni Panozzo <giovanni@panozzo.it> | 2017-08-28 13:20:50 +0300 |
---|---|---|
committer | Giovanni Panozzo <giovanni@panozzo.it> | 2017-08-28 13:20:50 +0300 |
commit | bfe150d2c60569f470e7d3600a4ed3c5e8cf40bf (patch) | |
tree | 0edca2add5e0d3a034da0a7e4aec25c8e224a6ba /remmina-plugins | |
parent | a412dad1f8dcbf5b4210aa3c910be813bbae7161 (diff) |
RDP client keyboard mapping with GTK3
Diffstat (limited to 'remmina-plugins')
-rw-r--r-- | remmina-plugins/rdp/rdp_event.c | 124 | ||||
-rw-r--r-- | remmina-plugins/rdp/rdp_plugin.c | 8 | ||||
-rw-r--r-- | remmina-plugins/rdp/rdp_plugin.h | 2 |
3 files changed, 88 insertions, 46 deletions
diff --git a/remmina-plugins/rdp/rdp_event.c b/remmina-plugins/rdp/rdp_event.c index 7ae78c646..0de609d21 100644 --- a/remmina-plugins/rdp/rdp_event.c +++ b/remmina-plugins/rdp/rdp_event.c @@ -41,7 +41,6 @@ #include <gdk/gdkkeysyms.h> #include <cairo/cairo-xlib.h> #include <freerdp/locale/keyboard.h> -#include <X11/XKBlib.h> #include <execinfo.h> static void remmina_rdp_event_on_focus_in(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp) @@ -102,40 +101,48 @@ void remmina_rdp_event_event_push(RemminaProtocolWidget* gp, const RemminaPlugin } } -static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, DWORD scancode) +static void remmina_rdp_event_release_all_keys(RemminaProtocolWidget* gp) { - TRACE_CALL("remmina_rdp_event_release_key"); - gint i, k; + TRACE_CALL("remmina_rdp_event_release_all_keys"); rfContext* rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event = { 0 }; - DWORD pressed_scancode; - - rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE; + int i; - if (scancode == 0) + /* Send all release key events for previously pressed keys */ + for (i = 0; i < rfi->pressed_keys->len; i++) { - /* Send all release key events for previously pressed keys */ - rdp_event.key_event.up = True; - - for (i = 0; i < rfi->pressed_keys->len; i++) - { - pressed_scancode = g_array_index(rfi->pressed_keys, DWORD, i); - rdp_event.key_event.key_code = pressed_scancode & 0xFF; - rdp_event.key_event.extended = pressed_scancode & 0x100; - rdp_event.key_event.up = 1; + rdp_event = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i); + if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE || + rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE) && + rdp_event.key_event.up == False) { + rdp_event.key_event.up = True; remmina_rdp_event_event_push(gp, &rdp_event); } - - g_array_set_size(rfi->pressed_keys, 0); } - else - { + + g_array_set_size(rfi->pressed_keys, 0); +} + +static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, RemminaPluginRdpEvent rdp_event) +{ + TRACE_CALL("remmina_rdp_event_release_key"); + gint i; + rfContext* rfi = GET_PLUGIN_DATA(gp); + RemminaPluginRdpEvent rdp_event_2 = { 0 }; + + rdp_event_2.type = REMMINA_RDP_EVENT_TYPE_SCANCODE; + + if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE || + rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE) && + rdp_event.key_event.up ) { /* Unregister the keycode only */ for (i = 0; i < rfi->pressed_keys->len; i++) { - k = g_array_index(rfi->pressed_keys, DWORD, i); + rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i); - if (k == scancode) + if (rdp_event_2.key_event.key_code == rdp_event.key_event.key_code && + rdp_event_2.key_event.unicode_code == rdp_event.key_event.unicode_code && + rdp_event_2.key_event.extended == rdp_event.key_event.extended) { g_array_remove_index_fast(rfi->pressed_keys, i); break; @@ -144,6 +151,22 @@ static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, DWORD scanc } } +static void keypress_list_add(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event) +{ + TRACE_CALL("keypress_list_add"); + rfContext* rfi = GET_PLUGIN_DATA(gp); + if (!rdp_event.key_event.key_code) + return; + + if (rdp_event.key_event.up) { + remmina_rdp_event_release_key(gp, rdp_event); + } else { + g_array_append_val(rfi->pressed_keys, rdp_event); + } + +} + + static void remmina_rdp_event_scale_area(RemminaProtocolWidget* gp, gint* x, gint* y, gint* w, gint* h) { TRACE_CALL("remmina_rdp_event_scale_area"); @@ -515,7 +538,7 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, { TRACE_CALL("remmina_rdp_event_on_key"); GdkDisplay* display; - KeyCode cooked_keycode; + guint32 unicode_keyval; rfContext* rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event; DWORD scancode = 0; @@ -538,6 +561,11 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, switch (event->keyval) { case GDK_KEY_Pause: + /* + * See https://msdn.microsoft.com/en-us/library/cc240584.aspx + * 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT) + * for pause key management + */ rdp_event.key_event.key_code = 0x1D; rdp_event.key_event.up = False; remmina_rdp_event_event_push(gp, &rdp_event); @@ -558,33 +586,37 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode); rdp_event.key_event.key_code = scancode & 0xFF; rdp_event.key_event.extended = scancode & 0x100; + if (rdp_event.key_event.key_code) { + remmina_rdp_event_event_push(gp, &rdp_event); + keypress_list_add(gp, rdp_event); + } } 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)); - cooked_keycode = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XkbKeycodeToKeysym(GDK_DISPLAY_XDISPLAY(display), event->hardware_keycode, 0, 0)); - scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(cooked_keycode); - rdp_event.key_event.key_code = scancode & 0xFF; - rdp_event.key_event.extended = scancode & 0x100; + display = gtk_widget_get_display(widget); // ToDo: get correct display for this window! + unicode_keyval = gdk_keyval_to_unicode(event->keyval); + if (unicode_keyval == 0 || unicode_keyval == 0x0D) { + // When unicode_keyval == 0 (unknown unicode char, i.e. shift or alt o ctrl key) + // or unicode_keyval == Enter + // we fallback to not locally-map the key + scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode); + rdp_event.key_event.key_code = scancode & 0xFF; + rdp_event.key_event.extended = scancode & 0x100; + if (rdp_event.key_event.key_code) { + remmina_rdp_event_event_push(gp, &rdp_event); + keypress_list_add(gp, rdp_event); + } + } else { + rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE; + rdp_event.key_event.unicode_code = unicode_keyval; + rdp_event.key_event.extended = False; + remmina_rdp_event_event_push(gp, &rdp_event); + keypress_list_add(gp, rdp_event); + } } - - 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, scancode); - else - remmina_rdp_event_release_key(gp, scancode); - } - return TRUE; } @@ -659,7 +691,7 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp) rfi->clipboard.clipboard_handler = g_signal_connect(clipboard, "owner-change", G_CALLBACK(remmina_rdp_event_on_clipboard), gp); } - rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof (DWORD)); + rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof (RemminaPluginRdpEvent)); rfi->event_queue = g_async_queue_new_full(g_free); rfi->ui_queue = g_async_queue_new(); pthread_mutex_init(&rfi->ui_queue_mutex, NULL); @@ -955,7 +987,7 @@ static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget* gp, Remmina void remmina_rdp_event_unfocus(RemminaProtocolWidget* gp) { TRACE_CALL("remmina_rdp_event_unfocus"); - remmina_rdp_event_release_key(gp, 0); + remmina_rdp_event_release_all_keys(gp); } static void remmina_rdp_event_process_event(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) diff --git a/remmina-plugins/rdp/rdp_plugin.c b/remmina-plugins/rdp/rdp_plugin.c index 0a8c16d83..39b0d44e7 100644 --- a/remmina-plugins/rdp/rdp_plugin.c +++ b/remmina-plugins/rdp/rdp_plugin.c @@ -88,6 +88,14 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget* gp) input->KeyboardEvent(input, flags, event->key_event.key_code); break; + case REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE: + /* + * TS_UNICODE_KEYBOARD_EVENT RDP message, see https://msdn.microsoft.com/en-us/library/cc240585.aspx + */ + flags = event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN; + input->UnicodeKeyboardEvent(input, flags, event->key_event.unicode_code); + break; + case REMMINA_RDP_EVENT_TYPE_MOUSE: if (event->mouse_event.extended) input->ExtendedMouseEvent(input, event->mouse_event.flags, diff --git a/remmina-plugins/rdp/rdp_plugin.h b/remmina-plugins/rdp/rdp_plugin.h index 940be47e8..5a8c60700 100644 --- a/remmina-plugins/rdp/rdp_plugin.h +++ b/remmina-plugins/rdp/rdp_plugin.h @@ -109,6 +109,7 @@ typedef struct rf_glyph rfGlyph; typedef enum { REMMINA_RDP_EVENT_TYPE_SCANCODE, + REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE, REMMINA_RDP_EVENT_TYPE_MOUSE, REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_LIST, REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_DATA_RESPONSE, @@ -125,6 +126,7 @@ struct remmina_plugin_rdp_event BOOL up; BOOL extended; UINT8 key_code; + UINT32 unicode_code; } key_event; struct { |