diff mbox series

[10/10] ui/gtk: use native keyboard scancodes on Windows

Message ID 20200510184304.9267-10-vr_qemu@t-online.de
State New
Headers show
Series [01/10] ui/win32-kbd-hook: handle AltGr in a hook procedure | expand

Commit Message

Volker Rümelin May 10, 2020, 6:43 p.m. UTC
Since GTK 3.22 the function gdk_event_get_scancode() is
available. On Windows this function returns keyboard scancodes
and some extended flags. These raw keyboard scancodes are much
better suited for this use case than the half-cooked win32
virtual-key codes because scancodes report the key position on
the keyboard and the positions are independent of national
language settings.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 ui/gtk.c | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

Comments

Daniel P. Berrangé May 12, 2020, 11:31 a.m. UTC | #1
On Sun, May 10, 2020 at 08:43:04PM +0200, Volker Rümelin wrote:
> Since GTK 3.22 the function gdk_event_get_scancode() is
> available. On Windows this function returns keyboard scancodes
> and some extended flags. These raw keyboard scancodes are much
> better suited for this use case than the half-cooked win32
> virtual-key codes because scancodes report the key position on
> the keyboard and the positions are independent of national
> language settings.
> 
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
> ---
>  ui/gtk.c | 33 +++++++++++++++++++++++++++++----
>  1 file changed, 29 insertions(+), 4 deletions(-)
> 
> diff --git a/ui/gtk.c b/ui/gtk.c
> index a43fddc57f..242b378bf1 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -1016,8 +1016,13 @@ static const guint16 *gd_get_keymap(size_t *maplen)
>  #ifdef GDK_WINDOWING_WIN32
>      if (GDK_IS_WIN32_DISPLAY(dpy)) {
>          trace_gd_keymap_windowing("win32");
> +#if GTK_CHECK_VERSION(3, 22, 0)
> +        *maplen = qemu_input_map_atset1_to_qcode_len;
> +        return qemu_input_map_atset1_to_qcode;
> +#else
>          *maplen = qemu_input_map_win32_to_qcode_len;
>          return qemu_input_map_win32_to_qcode;
> +#endif

Our current min GTK is 3.14, which I picked here:

commit 58296cb61866195297510e946a51acc5f0b9639e
Author: Daniel P. Berrangé <berrange@redhat.com>
Date:   Wed Aug 22 14:15:53 2018 +0100

    ui: increase min required GTK3 version to 3.14.0
    
    Per supported platforms doc[1], the various min GTK3 on relevant distros is:
    
      RHEL-7.0: 3.8.8
      RHEL-7.2: 3.14.13
      RHEL-7.4: 3.22.10
      RHEL-7.5: 3.22.26
      Debian (Stretch): 3.22.11
      Debian (Jessie): 3.14.5
      OpenBSD (Ports): 3.22.30
      FreeBSD (Ports): 3.22.29
      OpenSUSE Leap 15: 3.22.30
      SLE12-SP2: Unknown
      Ubuntu (Xenial): 3.18.9
      macOS (Homebrew): 3.22.30
    
    This suggests that a minimum GTK3 of 3.14.0 is a reasonable target,
    as users are unlikely to be stuck on RHEL-7.0/7.1 still
    


since that time, we no longer support Debian Jessie, since Debian Buster
is now released. We also no longer support Ubuntu Xenial (16.04), since
we now only need Ubuntu Bionic (18.04) and Focal (20.04).

So we can justify moving the minium Gtk in QEMU to 3.22 at this time.

This will avoid you needing to do versioned ifdef for this new functionality.


Regards,
Daniel
Volker Rümelin May 14, 2020, 8:46 p.m. UTC | #2
> since that time, we no longer support Debian Jessie, since Debian Buster
> is now released. We also no longer support Ubuntu Xenial (16.04), since
> we now only need Ubuntu Bionic (18.04) and Focal (20.04).
>
> So we can justify moving the minium Gtk in QEMU to 3.22 at this time.
>
> This will avoid you needing to do versioned ifdef for this new functionality.

Hi Daniel,

I noticed there are already seven versioned ifdefs in ui/gtk.c. I would prefer to leave my patch as it is at the moment and send in a separate follow up patch which increases the minimum GTK version in configure to 3.22 and removes all versioned code in ui/gtk.c. Just like your patch from 2018. I think this is easier to revert if someone complains about the removal.

With best regards,
Volker
diff mbox series

Patch

diff --git a/ui/gtk.c b/ui/gtk.c
index a43fddc57f..242b378bf1 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1016,8 +1016,13 @@  static const guint16 *gd_get_keymap(size_t *maplen)
 #ifdef GDK_WINDOWING_WIN32
     if (GDK_IS_WIN32_DISPLAY(dpy)) {
         trace_gd_keymap_windowing("win32");
+#if GTK_CHECK_VERSION(3, 22, 0)
+        *maplen = qemu_input_map_atset1_to_qcode_len;
+        return qemu_input_map_atset1_to_qcode;
+#else
         *maplen = qemu_input_map_win32_to_qcode_len;
         return qemu_input_map_win32_to_qcode;
+#endif
     }
 #endif
 
@@ -1063,6 +1068,25 @@  static int gd_map_keycode(int scancode)
     return keycode_map[scancode];
 }
 
+static int gd_get_keycode(GdkEventKey *key)
+{
+#if defined G_OS_WIN32 && GTK_CHECK_VERSION(3, 22, 0)
+    int scancode = gdk_event_get_scancode((GdkEvent *)key);
+
+    /* translate Windows native scan codes to atset1 keycodes */
+    switch (scancode & (KF_EXTENDED | 0xff)) {
+    case 0x145:     /* NUMLOCK */
+        return scancode & 0xff;
+    }
+
+    return scancode & KF_EXTENDED ?
+        0xe000 | (scancode & 0xff) : scancode & 0xff;
+
+#else
+    return key->hardware_keycode;
+#endif
+}
+
 static gboolean gd_text_key_down(GtkWidget *widget,
                                  GdkEventKey *key, void *opaque)
 {
@@ -1074,7 +1098,7 @@  static gboolean gd_text_key_down(GtkWidget *widget,
     } else if (key->length) {
         kbd_put_string_console(con, key->string, key->length);
     } else {
-        int qcode = gd_map_keycode(key->hardware_keycode);
+        int qcode = gd_map_keycode(gd_get_keycode(key));
         kbd_put_qcode_console(con, qcode, false);
     }
     return TRUE;
@@ -1083,7 +1107,7 @@  static gboolean gd_text_key_down(GtkWidget *widget,
 static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
 {
     VirtualConsole *vc = opaque;
-    int qcode;
+    int keycode, qcode;
 
 #ifdef G_OS_WIN32
     /* on windows, we ought to ignore the reserved key event? */
@@ -1111,9 +1135,10 @@  static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
         return TRUE;
     }
 
-    qcode = gd_map_keycode(key->hardware_keycode);
+    keycode = gd_get_keycode(key);
+    qcode = gd_map_keycode(keycode);
 
-    trace_gd_key_event(vc->label, key->hardware_keycode, qcode,
+    trace_gd_key_event(vc->label, keycode, qcode,
                        (key->type == GDK_KEY_PRESS) ? "down" : "up");
 
     qkbd_state_key_event(vc->gfx.kbd, qcode,