[gnome-remote-desktop] session-rdp: Add support for unicode input



commit 0caf5b1a14c76f179faeb2936eaa5f7cfaf450b5
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Fri Dec 18 11:28:29 2020 +0100

    session-rdp: Add support for unicode input
    
    In addition to keyboard input via keycodes, RDP also supports input
    of Unicode characters.
    This does not replace keyboard input via keycodes (keyboard input via
    keycodes is still the expected way of keyboard input), but allows
    clients to input specific characters this way.
    Remmina, for example, makes use of it.
    
    To send mutter the Unicode character, convert it first into a keysym
    using xkbcommon.
    
    To be able to make use of that conversion function, convert the Unicode
    character first from UTF-16 to UTF-32, as xkbcommon can only convert
    UTF-32 characters into a keysym.
    Then submit the keysym to mutter to input that character.

 meson.build           |  2 ++
 src/grd-session-rdp.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/meson.build       |  3 ++-
 3 files changed, 63 insertions(+), 2 deletions(-)
---
diff --git a/meson.build b/meson.build
index af423a4..6a0c905 100644
--- a/meson.build
+++ b/meson.build
@@ -5,6 +5,7 @@ project('gnome-remote-desktop', 'c',
                           'buildtype=debugoptimized'])
 
 freerdp_req = '>= 2.2.0'
+xkbcommon_req = '>= 1.0.0'
 
 gnome = import('gnome')
 
@@ -20,6 +21,7 @@ libvncclient_dep = dependency('libvncclient')
 libsecret_dep = dependency('libsecret-1')
 libnotify_dep = dependency('libnotify')
 winpr_dep = dependency('winpr2', version: freerdp_req)
+xkbcommon_dep = dependency('xkbcommon', version: xkbcommon_req)
 
 cdata = configuration_data()
 cdata.set_quoted('GETTEXT_PACKAGE', 'gnome-remote-desktop')
diff --git a/src/grd-session-rdp.c b/src/grd-session-rdp.c
index bb44a0f..8714346 100644
--- a/src/grd-session-rdp.c
+++ b/src/grd-session-rdp.c
@@ -25,6 +25,7 @@
 #include <freerdp/peer.h>
 #include <gio/gio.h>
 #include <linux/input-event-codes.h>
+#include <xkbcommon/xkbcommon.h>
 
 #include "grd-context.h"
 #include "grd-damage-utils.h"
@@ -78,6 +79,8 @@ struct _GrdSessionRdp
   uint16_t pointer_x;
   uint16_t pointer_y;
 
+  GHashTable *pressed_unicode_keys;
+
   GThreadPool *thread_pool;
   GCond pending_jobs_cond;
   GMutex pending_jobs_mutex;
@@ -1011,15 +1014,34 @@ rdp_peer_refresh_region (freerdp_peer   *peer,
   ++rdp_peer_context->frame_id;
 }
 
+static gboolean
+notify_keysym_released (gpointer key,
+                        gpointer value,
+                        gpointer user_data)
+{
+  GrdSession *session = (GrdSession *) user_data;
+  xkb_keysym_t keysym = GPOINTER_TO_UINT (key);
+
+  grd_session_notify_keyboard_keysym (session, keysym, GRD_KEY_STATE_RELEASED);
+
+  return TRUE;
+}
+
 static BOOL
 rdp_input_synchronize_event (rdpInput *rdp_input,
                              uint32_t  flags)
 {
   RdpPeerContext *rdp_peer_context = (RdpPeerContext *) rdp_input->context;
+  GrdSessionRdp *session_rdp = rdp_peer_context->session_rdp;
+  GrdSession *session = GRD_SESSION (session_rdp);
 
   if (!(rdp_peer_context->flags & RDP_PEER_ACTIVATED))
     return TRUE;
 
+  g_hash_table_foreach_remove (session_rdp->pressed_unicode_keys,
+                               notify_keysym_released,
+                               session);
+
   return TRUE;
 }
 
@@ -1135,15 +1157,44 @@ rdp_input_keyboard_event (rdpInput *rdp_input,
 static BOOL
 rdp_input_unicode_keyboard_event (rdpInput *rdp_input,
                                   uint16_t  flags,
-                                  uint16_t  code)
+                                  uint16_t  code_utf16)
 {
   RdpPeerContext *rdp_peer_context = (RdpPeerContext *) rdp_input->context;
   GrdSessionRdp *session_rdp = rdp_peer_context->session_rdp;
+  GrdSession *session = GRD_SESSION (session_rdp);
+  uint32_t *code_utf32;
+  xkb_keysym_t keysym;
+  GrdKeyState key_state;
 
   if (!(rdp_peer_context->flags & RDP_PEER_ACTIVATED) ||
       is_view_only (session_rdp))
     return TRUE;
 
+  code_utf32 = g_utf16_to_ucs4 (&code_utf16, 1, NULL, NULL, NULL);
+  if (!code_utf32)
+    return TRUE;
+
+  keysym = xkb_utf32_to_keysym (*code_utf32);
+  g_free (code_utf32);
+
+  key_state = flags & KBD_FLAGS_DOWN ? GRD_KEY_STATE_PRESSED
+                                     : GRD_KEY_STATE_RELEASED;
+
+  if (flags & KBD_FLAGS_DOWN)
+    {
+      if (!g_hash_table_add (session_rdp->pressed_unicode_keys,
+                             GUINT_TO_POINTER (keysym)))
+        return TRUE;
+    }
+  else
+    {
+      if (!g_hash_table_remove (session_rdp->pressed_unicode_keys,
+                                GUINT_TO_POINTER (keysym)))
+        return TRUE;
+    }
+
+  grd_session_notify_keyboard_keysym (session, keysym, key_state);
+
   return TRUE;
 }
 
@@ -1336,6 +1387,7 @@ init_rdp_session (GrdSessionRdp *session_rdp,
   rdp_settings->NSCodec = TRUE;
   rdp_settings->FrameMarkerCommandEnabled = TRUE;
   rdp_settings->SurfaceFrameMarkerEnabled = TRUE;
+  rdp_settings->UnicodeInput = TRUE;
 
   peer->Capabilities = rdp_peer_capabilities;
   peer->PostConnect = rdp_peer_post_connect;
@@ -1489,6 +1541,10 @@ grd_session_rdp_stop (GrdSession *session)
   freerdp_peer_context_free (peer);
   freerdp_peer_free (peer);
 
+  g_hash_table_foreach_remove (session_rdp->pressed_unicode_keys,
+                               notify_keysym_released,
+                               session);
+
   g_clear_pointer (&session_rdp->last_frame, g_free);
   g_hash_table_foreach_remove (session_rdp->pointer_cache,
                                clear_pointer_bitmap,
@@ -1549,6 +1605,7 @@ grd_session_rdp_dispose (GObject *object)
 {
   GrdSessionRdp *session_rdp = GRD_SESSION_RDP (object);
 
+  g_clear_pointer (&session_rdp->pressed_unicode_keys, g_hash_table_unref);
   g_clear_pointer (&session_rdp->pointer_cache, g_hash_table_unref);
 
   G_OBJECT_CLASS (grd_session_rdp_parent_class)->dispose (object);
@@ -1584,6 +1641,7 @@ static void
 grd_session_rdp_init (GrdSessionRdp *session_rdp)
 {
   session_rdp->pointer_cache = g_hash_table_new (NULL, are_pointer_bitmaps_equal);
+  session_rdp->pressed_unicode_keys = g_hash_table_new (NULL, NULL);
 
   g_cond_init (&session_rdp->pending_jobs_cond);
   g_mutex_init (&session_rdp->pending_jobs_mutex);
diff --git a/src/meson.build b/src/meson.build
index 1b6425d..5dc54ae 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -66,7 +66,8 @@ executable('gnome-remote-desktop-daemon',
                           libvncserver_dep,
                           libsecret_dep,
                           libnotify_dep,
-                          winpr_dep],
+                          winpr_dep,
+                          xkbcommon_dep],
            include_directories: [configinc],
            install: true,
            install_dir: libexecdir)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]