• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revisiónad5a59124c251abd7e725fa3f6a3308c06d6b486 (tree)
Tiempo2020-05-21 22:48:15
AutorPeter Maydell <peter.maydell@lina...>
CommiterPeter Maydell

Log Message

ui: windows keyboard fixes for gtk & sdl.
ui: require GTK 3.22 or newer.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAABCgAGBQJexO1MAAoJEEy22O7T6HE4xLEP/jHTGFdh7Sz5iyRQ/fD8HJdS
gMeLgPznDHMYoVhEtXPk90Y25cFvr4r0Y2Io1D6fyKK/hbyKRNKIj7JleAhH2aPY
MYfGbY4sjyNuxG6b6mXOTqQSI6IBmvrPuZyOPh46LzRSTANpP9Mn/zl1B2DqzBnV
z+N/Yq/+f2TMZGPVjzOtsOfomGADXF96naWaaKdAI/o2OD0xFIw/pfHjjiOud2To
7+rQLwhzdmDsNZfcwZqq6H/8TXpUrUqe4OxSMAlyzidW5dZQYa4EIre1pyc9Y51o
C69wnD4wqGyJ93jUbZM/60owUYQ8wuvO98Gx27Ofqluuz3tTDrz+dMRVKxSw7AOC
xZDhPzKTJcg9XeWE7sYzu3+nwXW/h8D9xFLu3RYKmPXCsVs9BwXJM5O3jsRc6kSt
62eqXsh4oAXxqJZSwH0uGMTrnKO7TGNscgmmFEUj+kT95sjiYegTYKHagubDiLCP
6Z1f7svueinCvLGwj79IEBdueSCIHMf5nB87aIPxGkaaI958Eb2y/parnPYrAzag
IXrniGL2qx/TSUzaR5nRAkA4bd3zVaNrO5r/4cBWBF0SgZ9disICdO7vm6gVUpVt
VXG/EOTYvMgHiDKaJ+O2z9OVzRyWKoEotOKNjUG8Tgcq1zcGyt+MYpUv2c1B2Yay
lTctgEfn4zEQLFNQiOjN
=DIyS
-----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/ui-20200520-pull-request' into staging

ui: windows keyboard fixes for gtk & sdl.
ui: require GTK 3.22 or newer.

# gpg: Signature made Wed 20 May 2020 09:41:48 BST
# gpg: using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/ui-20200520-pull-request:

ui: increase min required GTK version to 3.22.0
ui/gtk: use native keyboard scancodes on Windows
ui/gtk: don't pass on win keys without keyboard grab
ui/sdl2-input: use trace-events to debug key events
ui/sdl2: start in full screen with grab enabled
ui/sdl2: fix handling of AltGr key on Windows
ui/gtk: remove unused variable ignore_keys
ui/gtk: remove unused code
ui/gkt: release all keys on grab-broken-event
ui/gtk: fix handling of AltGr key on Windows
ui/win32-kbd-hook: handle AltGr in a hook procedure

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Cambiar Resumen

Diferencia incremental

--- a/configure
+++ b/configure
@@ -2897,7 +2897,7 @@ fi
28972897 if test "$gtk" != "no"; then
28982898 gtkpackage="gtk+-3.0"
28992899 gtkx11package="gtk+-x11-3.0"
2900- gtkversion="3.14.0"
2900+ gtkversion="3.22.0"
29012901 if $pkg_config --exists "$gtkpackage >= $gtkversion"; then
29022902 gtk_cflags=$($pkg_config --cflags $gtkpackage)
29032903 gtk_libs=$($pkg_config --libs $gtkpackage)
--- /dev/null
+++ b/include/ui/win32-kbd-hook.h
@@ -0,0 +1,14 @@
1+/*
2+ * SPDX-License-Identifier: GPL-2.0-or-later
3+ *
4+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
5+ * See the COPYING file in the top-level directory.
6+ */
7+
8+#ifndef UI_WIN32_KBD_HOOK_H
9+#define UI_WIN32_KBD_HOOK_H
10+
11+void win32_kbd_set_window(void *hwnd);
12+void win32_kbd_set_grab(bool grab);
13+
14+#endif
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -32,6 +32,7 @@ stub-obj-y += trace-control.o
3232 stub-obj-y += uuid.o
3333 stub-obj-y += vm-stop.o
3434 stub-obj-y += vmstate.o
35+stub-obj-y += win32-kbd-hook.o
3536 stub-obj-y += fd-register.o
3637 stub-obj-y += qmp_memory_device.o
3738 stub-obj-y += target-monitor-defs.o
--- /dev/null
+++ b/stubs/win32-kbd-hook.c
@@ -0,0 +1,18 @@
1+/*
2+ * Win32 keyboard hook stubs
3+ *
4+ * This work is licensed under the terms of the GNU GPL, version 2 or
5+ * (at your option) any later version. See the COPYING file in the
6+ * top-level directory.
7+ */
8+
9+#include "qemu/osdep.h"
10+#include "ui/win32-kbd-hook.h"
11+
12+void win32_kbd_set_window(void *hwnd)
13+{
14+}
15+
16+void win32_kbd_set_grab(bool grab)
17+{
18+}
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -15,6 +15,9 @@ common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
1515 common-obj-$(CONFIG_COCOA) += cocoa.o
1616 common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
1717 common-obj-$(call lnot,$(CONFIG_VNC)) += vnc-stubs.o
18+ifneq (,$(findstring m,$(CONFIG_SDL)$(CONFIG_GTK)))
19+common-obj-$(CONFIG_WIN32) += win32-kbd-hook.o
20+endif
1821
1922 # ui-sdl module
2023 common-obj-$(CONFIG_SDL) += sdl.mo
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -38,6 +38,10 @@
3838
3939 #include "ui/console.h"
4040 #include "ui/gtk.h"
41+#ifdef G_OS_WIN32
42+#include <gdk/gdkwin32.h>
43+#endif
44+#include "ui/win32-kbd-hook.h"
4145
4246 #include <glib/gi18n.h>
4347 #include <locale.h>
@@ -108,15 +112,6 @@
108112 # define VTE_CHECK_VERSION(a, b, c) 0
109113 #endif
110114
111-/* Some older mingw versions lack this constant or have
112- * it conditionally defined */
113-#ifdef _WIN32
114-# ifndef MAPVK_VK_TO_VSC
115-# define MAPVK_VK_TO_VSC 0
116-# endif
117-#endif
118-
119-
120115 #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK)
121116
122117 static const guint16 *keycode_map;
@@ -173,8 +168,6 @@ struct GtkDisplayState {
173168
174169 bool external_pause_update;
175170
176- bool ignore_keys;
177-
178171 DisplayOptions *opts;
179172 };
180173
@@ -428,6 +421,16 @@ static void gd_widget_reparent(GtkWidget *from, GtkWidget *to,
428421 g_object_unref(G_OBJECT(widget));
429422 }
430423
424+static void *gd_win32_get_hwnd(VirtualConsole *vc)
425+{
426+#ifdef G_OS_WIN32
427+ return gdk_win32_window_get_impl_hwnd(
428+ gtk_widget_get_window(vc->window ? vc->window : vc->s->window));
429+#else
430+ return NULL;
431+#endif
432+}
433+
431434 /** DisplayState Callbacks **/
432435
433436 static void gd_update(DisplayChangeListener *dcl,
@@ -487,12 +490,7 @@ static void gd_refresh(DisplayChangeListener *dcl)
487490
488491 static GdkDevice *gd_get_pointer(GdkDisplay *dpy)
489492 {
490-#if GTK_CHECK_VERSION(3, 20, 0)
491493 return gdk_seat_get_pointer(gdk_display_get_default_seat(dpy));
492-#else
493- return gdk_device_manager_get_client_pointer(
494- gdk_display_get_device_manager(dpy));
495-#endif
496494 }
497495
498496 static void gd_mouse_set(DisplayChangeListener *dcl,
@@ -874,27 +872,18 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
874872
875873 if (!qemu_input_is_absolute() && s->ptr_owner == vc) {
876874 GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area);
875+ GdkDisplay *dpy = gtk_widget_get_display(widget);
876+ GdkWindow *win = gtk_widget_get_window(widget);
877+ GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
878+ GdkRectangle geometry;
877879 int screen_width, screen_height;
878880
879881 int x = (int)motion->x_root;
880882 int y = (int)motion->y_root;
881883
882-#if GTK_CHECK_VERSION(3, 22, 0)
883- {
884- GdkDisplay *dpy = gtk_widget_get_display(widget);
885- GdkWindow *win = gtk_widget_get_window(widget);
886- GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
887- GdkRectangle geometry;
888- gdk_monitor_get_geometry(monitor, &geometry);
889- screen_width = geometry.width;
890- screen_height = geometry.height;
891- }
892-#else
893- {
894- screen_width = gdk_screen_get_width(screen);
895- screen_height = gdk_screen_get_height(screen);
896- }
897-#endif
884+ gdk_monitor_get_geometry(monitor, &geometry);
885+ screen_width = geometry.width;
886+ screen_height = geometry.height;
898887
899888 /* In relative mode check to see if client pointer hit
900889 * one of the screen edges, and if so move it back by
@@ -1023,8 +1012,8 @@ static const guint16 *gd_get_keymap(size_t *maplen)
10231012 #ifdef GDK_WINDOWING_WIN32
10241013 if (GDK_IS_WIN32_DISPLAY(dpy)) {
10251014 trace_gd_keymap_windowing("win32");
1026- *maplen = qemu_input_map_win32_to_qcode_len;
1027- return qemu_input_map_win32_to_qcode;
1015+ *maplen = qemu_input_map_atset1_to_qcode_len;
1016+ return qemu_input_map_atset1_to_qcode;
10281017 }
10291018 #endif
10301019
@@ -1070,6 +1059,25 @@ static int gd_map_keycode(int scancode)
10701059 return keycode_map[scancode];
10711060 }
10721061
1062+static int gd_get_keycode(GdkEventKey *key)
1063+{
1064+#ifdef G_OS_WIN32
1065+ int scancode = gdk_event_get_scancode((GdkEvent *)key);
1066+
1067+ /* translate Windows native scancodes to atset1 keycodes */
1068+ switch (scancode & (KF_EXTENDED | 0xff)) {
1069+ case 0x145: /* NUMLOCK */
1070+ return scancode & 0xff;
1071+ }
1072+
1073+ return scancode & KF_EXTENDED ?
1074+ 0xe000 | (scancode & 0xff) : scancode & 0xff;
1075+
1076+#else
1077+ return key->hardware_keycode;
1078+#endif
1079+}
1080+
10731081 static gboolean gd_text_key_down(GtkWidget *widget,
10741082 GdkEventKey *key, void *opaque)
10751083 {
@@ -1081,7 +1089,7 @@ static gboolean gd_text_key_down(GtkWidget *widget,
10811089 } else if (key->length) {
10821090 kbd_put_string_console(con, key->string, key->length);
10831091 } else {
1084- int qcode = gd_map_keycode(key->hardware_keycode);
1092+ int qcode = gd_map_keycode(gd_get_keycode(key));
10851093 kbd_put_qcode_console(con, qcode, false);
10861094 }
10871095 return TRUE;
@@ -1090,18 +1098,19 @@ static gboolean gd_text_key_down(GtkWidget *widget,
10901098 static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
10911099 {
10921100 VirtualConsole *vc = opaque;
1093- GtkDisplayState *s = vc->s;
1094- int qcode;
1095-
1096- if (s->ignore_keys) {
1097- s->ignore_keys = (key->type == GDK_KEY_PRESS);
1098- return TRUE;
1099- }
1101+ int keycode, qcode;
11001102
1101-#ifdef WIN32
1103+#ifdef G_OS_WIN32
11021104 /* on windows, we ought to ignore the reserved key event? */
11031105 if (key->hardware_keycode == 0xff)
11041106 return false;
1107+
1108+ if (!vc->s->kbd_owner) {
1109+ if (key->hardware_keycode == VK_LWIN ||
1110+ key->hardware_keycode == VK_RWIN) {
1111+ return FALSE;
1112+ }
1113+ }
11051114 #endif
11061115
11071116 if (key->keyval == GDK_KEY_Pause
@@ -1117,9 +1126,10 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
11171126 return TRUE;
11181127 }
11191128
1120- qcode = gd_map_keycode(key->hardware_keycode);
1129+ keycode = gd_get_keycode(key);
1130+ qcode = gd_map_keycode(keycode);
11211131
1122- trace_gd_key_event(vc->label, key->hardware_keycode, qcode,
1132+ trace_gd_key_event(vc->label, keycode, qcode,
11231133 (key->type == GDK_KEY_PRESS) ? "down" : "up");
11241134
11251135 qkbd_state_key_event(vc->gfx.kbd, qcode,
@@ -1128,6 +1138,25 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
11281138 return TRUE;
11291139 }
11301140
1141+static gboolean gd_grab_broken_event(GtkWidget *widget,
1142+ GdkEventGrabBroken *event, void *opaque)
1143+{
1144+#ifdef CONFIG_WIN32
1145+ /*
1146+ * On Windows the Ctrl-Alt-Del key combination can't be grabbed. This
1147+ * key combination leaves all three keys in a stuck condition. We use
1148+ * the grab-broken-event to release all keys.
1149+ */
1150+ if (event->keyboard) {
1151+ VirtualConsole *vc = opaque;
1152+ GtkDisplayState *s = vc->s;
1153+
1154+ gtk_release_modifiers(s);
1155+ }
1156+#endif
1157+ return TRUE;
1158+}
1159+
11311160 static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque)
11321161 {
11331162 if (event->type == GDK_MOTION_NOTIFY) {
@@ -1180,7 +1209,6 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
11801209 gtk_notebook_set_current_page(nb, page);
11811210 gtk_widget_grab_focus(vc->focus);
11821211 }
1183- s->ignore_keys = false;
11841212 }
11851213
11861214 static void gd_accel_switch_vc(void *opaque)
@@ -1390,7 +1418,6 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
13901418 gd_update_full_redraw(vc);
13911419 }
13921420
1393-#if GTK_CHECK_VERSION(3, 20, 0)
13941421 static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr)
13951422 {
13961423 GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
@@ -1414,32 +1441,6 @@ static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr)
14141441 gdk_seat_ungrab(seat);
14151442 }
14161443 }
1417-#else
1418-static void gd_grab_devices(VirtualConsole *vc, bool grab,
1419- GdkInputSource source, GdkEventMask mask,
1420- GdkCursor *cursor)
1421-{
1422- GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
1423- GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
1424- GList *devs = gdk_device_manager_list_devices(mgr, GDK_DEVICE_TYPE_MASTER);
1425- GList *tmp = devs;
1426-
1427- for (tmp = devs; tmp; tmp = tmp->next) {
1428- GdkDevice *dev = tmp->data;
1429- if (gdk_device_get_source(dev) != source) {
1430- continue;
1431- }
1432- if (grab) {
1433- GdkWindow *win = gtk_widget_get_window(vc->gfx.drawing_area);
1434- gdk_device_grab(dev, win, GDK_OWNERSHIP_NONE, FALSE,
1435- mask, cursor, GDK_CURRENT_TIME);
1436- } else {
1437- gdk_device_ungrab(dev, GDK_CURRENT_TIME);
1438- }
1439- }
1440- g_list_free(devs);
1441-}
1442-#endif
14431444
14441445 static void gd_grab_keyboard(VirtualConsole *vc, const char *reason)
14451446 {
@@ -1451,13 +1452,8 @@ static void gd_grab_keyboard(VirtualConsole *vc, const char *reason)
14511452 }
14521453 }
14531454
1454-#if GTK_CHECK_VERSION(3, 20, 0)
1455+ win32_kbd_set_grab(true);
14551456 gd_grab_update(vc, true, vc->s->ptr_owner == vc);
1456-#else
1457- gd_grab_devices(vc, true, GDK_SOURCE_KEYBOARD,
1458- GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
1459- NULL);
1460-#endif
14611457 vc->s->kbd_owner = vc;
14621458 gd_update_caption(vc->s);
14631459 trace_gd_grab(vc->label, "kbd", reason);
@@ -1472,11 +1468,8 @@ static void gd_ungrab_keyboard(GtkDisplayState *s)
14721468 }
14731469 s->kbd_owner = NULL;
14741470
1475-#if GTK_CHECK_VERSION(3, 20, 0)
1471+ win32_kbd_set_grab(false);
14761472 gd_grab_update(vc, false, vc->s->ptr_owner == vc);
1477-#else
1478- gd_grab_devices(vc, false, GDK_SOURCE_KEYBOARD, 0, NULL);
1479-#endif
14801473 gd_update_caption(s);
14811474 trace_gd_ungrab(vc->label, "kbd");
14821475 }
@@ -1493,21 +1486,9 @@ static void gd_grab_pointer(VirtualConsole *vc, const char *reason)
14931486 }
14941487 }
14951488
1496-#if GTK_CHECK_VERSION(3, 20, 0)
14971489 gd_grab_update(vc, vc->s->kbd_owner == vc, true);
14981490 gdk_device_get_position(gd_get_pointer(display),
14991491 NULL, &vc->s->grab_x_root, &vc->s->grab_y_root);
1500-#else
1501- gd_grab_devices(vc, true, GDK_SOURCE_MOUSE,
1502- GDK_POINTER_MOTION_MASK |
1503- GDK_BUTTON_PRESS_MASK |
1504- GDK_BUTTON_RELEASE_MASK |
1505- GDK_BUTTON_MOTION_MASK |
1506- GDK_SCROLL_MASK,
1507- vc->s->null_cursor);
1508- gdk_device_get_position(gd_get_pointer(display),
1509- NULL, &vc->s->grab_x_root, &vc->s->grab_y_root);
1510-#endif
15111492 vc->s->ptr_owner = vc;
15121493 gd_update_caption(vc->s);
15131494 trace_gd_grab(vc->label, "ptr", reason);
@@ -1524,17 +1505,10 @@ static void gd_ungrab_pointer(GtkDisplayState *s)
15241505 s->ptr_owner = NULL;
15251506
15261507 display = gtk_widget_get_display(vc->gfx.drawing_area);
1527-#if GTK_CHECK_VERSION(3, 20, 0)
15281508 gd_grab_update(vc, vc->s->kbd_owner == vc, false);
15291509 gdk_device_warp(gd_get_pointer(display),
15301510 gtk_widget_get_screen(vc->gfx.drawing_area),
15311511 vc->s->grab_x_root, vc->s->grab_y_root);
1532-#else
1533- gd_grab_devices(vc, false, GDK_SOURCE_MOUSE, 0, NULL);
1534- gdk_device_warp(gd_get_pointer(display),
1535- gtk_widget_get_screen(vc->gfx.drawing_area),
1536- vc->s->grab_x_root, vc->s->grab_y_root);
1537-#endif
15381512 gd_update_caption(s);
15391513 trace_gd_ungrab(vc->label, "ptr");
15401514 }
@@ -1614,12 +1588,22 @@ static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing,
16141588 return TRUE;
16151589 }
16161590
1591+static gboolean gd_focus_in_event(GtkWidget *widget,
1592+ GdkEventFocus *event, gpointer opaque)
1593+{
1594+ VirtualConsole *vc = opaque;
1595+
1596+ win32_kbd_set_window(gd_win32_get_hwnd(vc));
1597+ return TRUE;
1598+}
1599+
16171600 static gboolean gd_focus_out_event(GtkWidget *widget,
1618- GdkEventCrossing *crossing, gpointer opaque)
1601+ GdkEventFocus *event, gpointer opaque)
16191602 {
16201603 VirtualConsole *vc = opaque;
16211604 GtkDisplayState *s = vc->s;
16221605
1606+ win32_kbd_set_window(NULL);
16231607 gtk_release_modifiers(s);
16241608 return TRUE;
16251609 }
@@ -1878,10 +1862,14 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
18781862 G_CALLBACK(gd_enter_event), vc);
18791863 g_signal_connect(vc->gfx.drawing_area, "leave-notify-event",
18801864 G_CALLBACK(gd_leave_event), vc);
1865+ g_signal_connect(vc->gfx.drawing_area, "focus-in-event",
1866+ G_CALLBACK(gd_focus_in_event), vc);
18811867 g_signal_connect(vc->gfx.drawing_area, "focus-out-event",
18821868 G_CALLBACK(gd_focus_out_event), vc);
18831869 g_signal_connect(vc->gfx.drawing_area, "configure-event",
18841870 G_CALLBACK(gd_configure), vc);
1871+ g_signal_connect(vc->gfx.drawing_area, "grab-broken-event",
1872+ G_CALLBACK(gd_grab_broken_event), vc);
18851873 } else {
18861874 g_signal_connect(vc->gfx.drawing_area, "key-press-event",
18871875 G_CALLBACK(gd_text_key_down), vc);
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -27,6 +27,7 @@
2727 #include "ui/console.h"
2828 #include "ui/input.h"
2929 #include "ui/sdl2.h"
30+#include "trace.h"
3031
3132 void sdl2_process_key(struct sdl2_console *scon,
3233 SDL_KeyboardEvent *ev)
@@ -38,6 +39,8 @@ void sdl2_process_key(struct sdl2_console *scon,
3839 return;
3940 }
4041 qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode];
42+ trace_sdl2_process_key(ev->keysym.scancode, qcode,
43+ ev->type == SDL_KEYDOWN ? "down" : "up");
4144 qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN);
4245
4346 if (!qemu_console_is_graphic(con)) {
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -30,6 +30,7 @@
3030 #include "ui/sdl2.h"
3131 #include "sysemu/runstate.h"
3232 #include "sysemu/sysemu.h"
33+#include "ui/win32-kbd-hook.h"
3334
3435 static int sdl2_num_outputs;
3536 static struct sdl2_console *sdl2_console;
@@ -220,6 +221,7 @@ static void sdl_grab_start(struct sdl2_console *scon)
220221 }
221222 SDL_SetWindowGrab(scon->real_window, SDL_TRUE);
222223 gui_grab = 1;
224+ win32_kbd_set_grab(true);
223225 sdl_update_caption(scon);
224226 }
225227
@@ -227,6 +229,7 @@ static void sdl_grab_end(struct sdl2_console *scon)
227229 {
228230 SDL_SetWindowGrab(scon->real_window, SDL_FALSE);
229231 gui_grab = 0;
232+ win32_kbd_set_grab(false);
230233 sdl_show_cursor(scon);
231234 sdl_update_caption(scon);
232235 }
@@ -325,6 +328,19 @@ static int get_mod_state(void)
325328 }
326329 }
327330
331+static void *sdl2_win32_get_hwnd(struct sdl2_console *scon)
332+{
333+#ifdef CONFIG_WIN32
334+ SDL_SysWMinfo info;
335+
336+ SDL_VERSION(&info.version);
337+ if (SDL_GetWindowWMInfo(scon->real_window, &info)) {
338+ return info.info.win.window;
339+ }
340+#endif
341+ return NULL;
342+}
343+
328344 static void handle_keydown(SDL_Event *ev)
329345 {
330346 int win;
@@ -544,6 +560,11 @@ static void handle_windowevent(SDL_Event *ev)
544560 sdl2_redraw(scon);
545561 break;
546562 case SDL_WINDOWEVENT_FOCUS_GAINED:
563+ win32_kbd_set_grab(gui_grab);
564+ if (qemu_console_is_graphic(scon->dcl.con)) {
565+ win32_kbd_set_window(sdl2_win32_get_hwnd(scon));
566+ }
567+ /* fall through */
547568 case SDL_WINDOWEVENT_ENTER:
548569 if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) {
549570 absolute_mouse_grab(scon);
@@ -558,6 +579,9 @@ static void handle_windowevent(SDL_Event *ev)
558579 scon->ignore_hotkeys = get_mod_state();
559580 break;
560581 case SDL_WINDOWEVENT_FOCUS_LOST:
582+ if (qemu_console_is_graphic(scon->dcl.con)) {
583+ win32_kbd_set_window(NULL);
584+ }
561585 if (gui_grab && !gui_fullscreen) {
562586 sdl_grab_end(scon);
563587 }
@@ -857,17 +881,16 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
857881 SDL_SetWindowIcon(sdl2_console[0].real_window, icon);
858882 }
859883
860- gui_grab = 0;
861- if (gui_fullscreen) {
862- sdl_grab_start(0);
863- }
864-
865884 mouse_mode_notifier.notify = sdl_mouse_mode_change;
866885 qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
867886
868887 sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
869888 sdl_cursor_normal = SDL_GetCursor();
870889
890+ if (gui_fullscreen) {
891+ sdl_grab_start(&sdl2_console[0]);
892+ }
893+
871894 atexit(sdl_cleanup);
872895 }
873896
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -75,6 +75,9 @@ input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value
7575 input_event_sync(void) ""
7676 input_mouse_mode(int absolute) "absolute %d"
7777
78+# sdl2-input.c
79+sdl2_process_key(int sdl_scancode, int qcode, const char *action) "translated SDL scancode %d to QKeyCode %d (%s)"
80+
7881 # spice-display.c
7982 qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d"
8083 qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u"
--- /dev/null
+++ b/ui/win32-kbd-hook.c
@@ -0,0 +1,102 @@
1+/*
2+ * This work is licensed under the terms of the GNU GPL, version 2 or
3+ * (at your option) any later version. See the COPYING file in the
4+ * top-level directory.
5+ *
6+ * The win32 keyboard hooking code was imported from project spice-gtk.
7+ */
8+
9+#include "qemu/osdep.h"
10+#include "sysemu/sysemu.h"
11+#include "ui/win32-kbd-hook.h"
12+
13+static Notifier win32_unhook_notifier;
14+static HHOOK win32_keyboard_hook;
15+static HWND win32_window;
16+static DWORD win32_grab;
17+
18+static LRESULT CALLBACK keyboard_hook_cb(int code, WPARAM wparam, LPARAM lparam)
19+{
20+ if (win32_window && code == HC_ACTION && win32_window == GetFocus()) {
21+ KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT *)lparam;
22+
23+ if (wparam != WM_KEYUP) {
24+ DWORD dwmsg = (hooked->flags << 24) |
25+ ((hooked->scanCode & 0xff) << 16) | 1;
26+
27+ switch (hooked->vkCode) {
28+ case VK_CAPITAL:
29+ /* fall through */
30+ case VK_SCROLL:
31+ /* fall through */
32+ case VK_NUMLOCK:
33+ /* fall through */
34+ case VK_LSHIFT:
35+ /* fall through */
36+ case VK_RSHIFT:
37+ /* fall through */
38+ case VK_RCONTROL:
39+ /* fall through */
40+ case VK_LMENU:
41+ /* fall through */
42+ case VK_RMENU:
43+ break;
44+
45+ case VK_LCONTROL:
46+ /*
47+ * When pressing AltGr, an extra VK_LCONTROL with a special
48+ * scancode with bit 9 set is sent. Let's ignore the extra
49+ * VK_LCONTROL, as that will make AltGr misbehave.
50+ */
51+ if (hooked->scanCode & 0x200) {
52+ return 1;
53+ }
54+ break;
55+
56+ default:
57+ if (win32_grab) {
58+ SendMessage(win32_window, wparam, hooked->vkCode, dwmsg);
59+ return 1;
60+ }
61+ break;
62+ }
63+
64+ } else {
65+ switch (hooked->vkCode) {
66+ case VK_LCONTROL:
67+ if (hooked->scanCode & 0x200) {
68+ return 1;
69+ }
70+ break;
71+ }
72+ }
73+ }
74+
75+ return CallNextHookEx(NULL, code, wparam, lparam);
76+}
77+
78+static void keyboard_hook_unhook(Notifier *n, void *data)
79+{
80+ UnhookWindowsHookEx(win32_keyboard_hook);
81+ win32_keyboard_hook = NULL;
82+}
83+
84+void win32_kbd_set_window(void *hwnd)
85+{
86+ if (hwnd && !win32_keyboard_hook) {
87+ /* note: the installing thread must have a message loop */
88+ win32_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_cb,
89+ GetModuleHandle(NULL), 0);
90+ if (win32_keyboard_hook) {
91+ win32_unhook_notifier.notify = keyboard_hook_unhook;
92+ qemu_add_exit_notifier(&win32_unhook_notifier);
93+ }
94+ }
95+
96+ win32_window = hwnd;
97+}
98+
99+void win32_kbd_set_grab(bool grab)
100+{
101+ win32_grab = grab;
102+}