From bd593d2cd9932ea20593c4e6960d84fd59854130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:05 +0200 Subject: ui/gtk: fix handling of AltGr key on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire up the keyboard hooking code on Windows to fix the AltGr key and improve keyboard grabbing. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-2-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index 83f2f5d49b..a0b10a1403 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -38,6 +38,10 @@ #include "ui/console.h" #include "ui/gtk.h" +#ifdef G_OS_WIN32 +#include +#endif +#include "ui/win32-kbd-hook.h" #include #include @@ -428,6 +432,16 @@ static void gd_widget_reparent(GtkWidget *from, GtkWidget *to, g_object_unref(G_OBJECT(widget)); } +static void *gd_win32_get_hwnd(VirtualConsole *vc) +{ +#ifdef G_OS_WIN32 + return gdk_win32_window_get_impl_hwnd( + gtk_widget_get_window(vc->window ? vc->window : vc->s->window)); +#else + return NULL; +#endif +} + /** DisplayState Callbacks **/ static void gd_update(DisplayChangeListener *dcl, @@ -1451,6 +1465,7 @@ static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) } } + win32_kbd_set_grab(true); #if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, true, vc->s->ptr_owner == vc); #else @@ -1472,6 +1487,7 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) } s->kbd_owner = NULL; + win32_kbd_set_grab(false); #if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, false, vc->s->ptr_owner == vc); #else @@ -1614,12 +1630,22 @@ static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, return TRUE; } +static gboolean gd_focus_in_event(GtkWidget *widget, + GdkEventFocus *event, gpointer opaque) +{ + VirtualConsole *vc = opaque; + + win32_kbd_set_window(gd_win32_get_hwnd(vc)); + return TRUE; +} + static gboolean gd_focus_out_event(GtkWidget *widget, - GdkEventCrossing *crossing, gpointer opaque) + GdkEventFocus *event, gpointer opaque) { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; + win32_kbd_set_window(NULL); gtk_release_modifiers(s); return TRUE; } @@ -1878,6 +1904,8 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) G_CALLBACK(gd_enter_event), vc); g_signal_connect(vc->gfx.drawing_area, "leave-notify-event", G_CALLBACK(gd_leave_event), vc); + g_signal_connect(vc->gfx.drawing_area, "focus-in-event", + G_CALLBACK(gd_focus_in_event), vc); g_signal_connect(vc->gfx.drawing_area, "focus-out-event", G_CALLBACK(gd_focus_out_event), vc); g_signal_connect(vc->gfx.drawing_area, "configure-event", -- cgit v1.2.3 From 0c4b1a7dc597499814d6222da4c95cbf9de68ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:06 +0200 Subject: ui/gkt: release all keys on grab-broken-event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no way to grab the Ctrl-Alt-Del key combination on Windows. This key combination will leave all three keys in a stuck condition. This patch uses the grab-broken-event to release the keys. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-3-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index a0b10a1403..655b26de38 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1142,6 +1142,25 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) return TRUE; } +static gboolean gd_grab_broken_event(GtkWidget *widget, + GdkEventGrabBroken *event, void *opaque) +{ +#ifdef CONFIG_WIN32 + /* + * On Windows the Ctrl-Alt-Del key combination can't be grabbed. This + * key combination leaves all three keys in a stuck condition. We use + * the grab-broken-event to release all keys. + */ + if (event->keyboard) { + VirtualConsole *vc = opaque; + GtkDisplayState *s = vc->s; + + gtk_release_modifiers(s); + } +#endif + return TRUE; +} + static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque) { if (event->type == GDK_MOTION_NOTIFY) { @@ -1910,6 +1929,8 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) G_CALLBACK(gd_focus_out_event), vc); g_signal_connect(vc->gfx.drawing_area, "configure-event", G_CALLBACK(gd_configure), vc); + g_signal_connect(vc->gfx.drawing_area, "grab-broken-event", + G_CALLBACK(gd_grab_broken_event), vc); } else { g_signal_connect(vc->gfx.drawing_area, "key-press-event", G_CALLBACK(gd_text_key_down), vc); -- cgit v1.2.3 From 9ef99eccb10002d785279d1fd1dc5b0f4c295bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:07 +0200 Subject: ui/gtk: remove unused code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code was last used before commit 2ec78706d1 "ui: convert GTK and SDL1 frontends to keycodemapdb". Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-4-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index 655b26de38..0e9503a0d1 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -112,15 +112,6 @@ # define VTE_CHECK_VERSION(a, b, c) 0 #endif -/* Some older mingw versions lack this constant or have - * it conditionally defined */ -#ifdef _WIN32 -# ifndef MAPVK_VK_TO_VSC -# define MAPVK_VK_TO_VSC 0 -# endif -#endif - - #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK) static const guint16 *keycode_map; -- cgit v1.2.3 From fd7c1bea17e4aaea45c00b37b7a2af5dd72b17f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:08 +0200 Subject: ui/gtk: remove unused variable ignore_keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the removal of GTK2 code in commit 89d85cde75 the code around ignore_keys is unused. See commit 1a01716a30 "gtk: Avoid accel key leakage into guest on console switch" why it was only needed for GTK2. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-5-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index 0e9503a0d1..354dd90e18 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -168,8 +168,6 @@ struct GtkDisplayState { bool external_pause_update; - bool ignore_keys; - DisplayOptions *opts; }; @@ -1095,14 +1093,8 @@ static gboolean gd_text_key_down(GtkWidget *widget, static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) { VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; int qcode; - if (s->ignore_keys) { - s->ignore_keys = (key->type == GDK_KEY_PRESS); - return TRUE; - } - #ifdef WIN32 /* on windows, we ought to ignore the reserved key event? */ if (key->hardware_keycode == 0xff) @@ -1204,7 +1196,6 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) gtk_notebook_set_current_page(nb, page); gtk_widget_grab_focus(vc->focus); } - s->ignore_keys = false; } static void gd_accel_switch_vc(void *opaque) -- cgit v1.2.3 From d3953bf7978521b6373cb8101f594cc44b0efa9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:12 +0200 Subject: ui/gtk: don't pass on win keys without keyboard grab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without keyboard grab Windows currently handles the two win keys and the key events are also sent to the guest. This is undesir- able. Only one program should handle key events. This patch ap- plies commit c68f74b02e "win32: do not handle win keys when the keyboard is not grabbed" from project spice-gtk to ui/gtk.c to fix this problem. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-9-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index 354dd90e18..1d51e14bb5 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1095,10 +1095,17 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) VirtualConsole *vc = opaque; int qcode; -#ifdef WIN32 +#ifdef G_OS_WIN32 /* on windows, we ought to ignore the reserved key event? */ if (key->hardware_keycode == 0xff) return false; + + if (!vc->s->kbd_owner) { + if (key->hardware_keycode == VK_LWIN || + key->hardware_keycode == VK_RWIN) { + return FALSE; + } + } #endif if (key->keyval == GDK_KEY_Pause -- cgit v1.2.3 From 145419274621f846385d35e609c051d4cbdd39a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:13 +0200 Subject: ui/gtk: use native keyboard scancodes on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-id: 20200516072014.7766-10-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index 1d51e14bb5..68a5b901c7 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1026,8 +1026,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 @@ -1073,6 +1078,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 scancodes 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) { @@ -1084,7 +1108,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; @@ -1093,7 +1117,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? */ @@ -1121,9 +1145,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, -- cgit v1.2.3 From 7b23d121f913709306e678a3289edc813f3a7463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:14 +0200 Subject: ui: increase min required GTK version to 3.22.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a mail on the qemu-devel mailing list at https://lists.nongnu.org/archive/html/qemu-devel/2020-05/msg02909.html and some internet research the GTK3 versions on supported platforms are: RHEL-7.4: 3.22.10 RHEL-7.5: 3.22.26 Debian (Stretch): 3.22.11 Debian (Buster): 3.24.5 OpenBSD (Ports): 3.22.30 FreeBSD (Ports): 3.22.29 OpenSUSE Leap 15: 3.22.30 SLE12-SP2: Unknown SLE15: 3.22.30 Ubuntu (Bionic): 3.22.30 Ubuntu (Focal): 3.24.18 macOS (Homebrew): 3.22.30 This justifies increasing the minimum required GTK version in QEMU to 3.22.0. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-11-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 91 ++++++---------------------------------------------------------- 1 file changed, 8 insertions(+), 83 deletions(-) (limited to 'ui/gtk.c') diff --git a/ui/gtk.c b/ui/gtk.c index 68a5b901c7..d4b49bd7da 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -490,12 +490,7 @@ static void gd_refresh(DisplayChangeListener *dcl) static GdkDevice *gd_get_pointer(GdkDisplay *dpy) { -#if GTK_CHECK_VERSION(3, 20, 0) return gdk_seat_get_pointer(gdk_display_get_default_seat(dpy)); -#else - return gdk_device_manager_get_client_pointer( - gdk_display_get_device_manager(dpy)); -#endif } static void gd_mouse_set(DisplayChangeListener *dcl, @@ -877,27 +872,18 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, if (!qemu_input_is_absolute() && s->ptr_owner == vc) { GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area); + GdkDisplay *dpy = gtk_widget_get_display(widget); + GdkWindow *win = gtk_widget_get_window(widget); + GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); + GdkRectangle geometry; int screen_width, screen_height; int x = (int)motion->x_root; int y = (int)motion->y_root; -#if GTK_CHECK_VERSION(3, 22, 0) - { - GdkDisplay *dpy = gtk_widget_get_display(widget); - GdkWindow *win = gtk_widget_get_window(widget); - GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); - GdkRectangle geometry; - gdk_monitor_get_geometry(monitor, &geometry); - screen_width = geometry.width; - screen_height = geometry.height; - } -#else - { - screen_width = gdk_screen_get_width(screen); - screen_height = gdk_screen_get_height(screen); - } -#endif + gdk_monitor_get_geometry(monitor, &geometry); + screen_width = geometry.width; + screen_height = geometry.height; /* In relative mode check to see if client pointer hit * one of the screen edges, and if so move it back by @@ -1026,13 +1012,8 @@ 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 @@ -1080,7 +1061,7 @@ static int gd_map_keycode(int scancode) static int gd_get_keycode(GdkEventKey *key) { -#if defined G_OS_WIN32 && GTK_CHECK_VERSION(3, 22, 0) +#ifdef G_OS_WIN32 int scancode = gdk_event_get_scancode((GdkEvent *)key); /* translate Windows native scancodes to atset1 keycodes */ @@ -1437,7 +1418,6 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) gd_update_full_redraw(vc); } -#if GTK_CHECK_VERSION(3, 20, 0) static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr) { GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); @@ -1461,32 +1441,6 @@ static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr) gdk_seat_ungrab(seat); } } -#else -static void gd_grab_devices(VirtualConsole *vc, bool grab, - GdkInputSource source, GdkEventMask mask, - GdkCursor *cursor) -{ - GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); - GdkDeviceManager *mgr = gdk_display_get_device_manager(display); - GList *devs = gdk_device_manager_list_devices(mgr, GDK_DEVICE_TYPE_MASTER); - GList *tmp = devs; - - for (tmp = devs; tmp; tmp = tmp->next) { - GdkDevice *dev = tmp->data; - if (gdk_device_get_source(dev) != source) { - continue; - } - if (grab) { - GdkWindow *win = gtk_widget_get_window(vc->gfx.drawing_area); - gdk_device_grab(dev, win, GDK_OWNERSHIP_NONE, FALSE, - mask, cursor, GDK_CURRENT_TIME); - } else { - gdk_device_ungrab(dev, GDK_CURRENT_TIME); - } - } - g_list_free(devs); -} -#endif static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) { @@ -1499,13 +1453,7 @@ static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) } win32_kbd_set_grab(true); -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, true, vc->s->ptr_owner == vc); -#else - gd_grab_devices(vc, true, GDK_SOURCE_KEYBOARD, - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, - NULL); -#endif vc->s->kbd_owner = vc; gd_update_caption(vc->s); trace_gd_grab(vc->label, "kbd", reason); @@ -1521,11 +1469,7 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) s->kbd_owner = NULL; win32_kbd_set_grab(false); -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, false, vc->s->ptr_owner == vc); -#else - gd_grab_devices(vc, false, GDK_SOURCE_KEYBOARD, 0, NULL); -#endif gd_update_caption(s); trace_gd_ungrab(vc->label, "kbd"); } @@ -1542,21 +1486,9 @@ static void gd_grab_pointer(VirtualConsole *vc, const char *reason) } } -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, vc->s->kbd_owner == vc, true); gdk_device_get_position(gd_get_pointer(display), NULL, &vc->s->grab_x_root, &vc->s->grab_y_root); -#else - gd_grab_devices(vc, true, GDK_SOURCE_MOUSE, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_SCROLL_MASK, - vc->s->null_cursor); - gdk_device_get_position(gd_get_pointer(display), - NULL, &vc->s->grab_x_root, &vc->s->grab_y_root); -#endif vc->s->ptr_owner = vc; gd_update_caption(vc->s); trace_gd_grab(vc->label, "ptr", reason); @@ -1573,17 +1505,10 @@ static void gd_ungrab_pointer(GtkDisplayState *s) s->ptr_owner = NULL; display = gtk_widget_get_display(vc->gfx.drawing_area); -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, vc->s->kbd_owner == vc, false); gdk_device_warp(gd_get_pointer(display), gtk_widget_get_screen(vc->gfx.drawing_area), vc->s->grab_x_root, vc->s->grab_y_root); -#else - gd_grab_devices(vc, false, GDK_SOURCE_MOUSE, 0, NULL); - gdk_device_warp(gd_get_pointer(display), - gtk_widget_get_screen(vc->gfx.drawing_area), - vc->s->grab_x_root, vc->s->grab_y_root); -#endif gd_update_caption(s); trace_gd_ungrab(vc->label, "ptr"); } -- cgit v1.2.3