Revisión | ad5a59124c251abd7e725fa3f6a3308c06d6b486 (tree) |
---|---|
Tiempo | 2020-05-21 22:48:15 |
Autor | Peter Maydell <peter.maydell@lina...> |
Commiter | Peter Maydell |
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:
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
@@ -2897,7 +2897,7 @@ fi | ||
2897 | 2897 | if test "$gtk" != "no"; then |
2898 | 2898 | gtkpackage="gtk+-3.0" |
2899 | 2899 | gtkx11package="gtk+-x11-3.0" |
2900 | - gtkversion="3.14.0" | |
2900 | + gtkversion="3.22.0" | |
2901 | 2901 | if $pkg_config --exists "$gtkpackage >= $gtkversion"; then |
2902 | 2902 | gtk_cflags=$($pkg_config --cflags $gtkpackage) |
2903 | 2903 | gtk_libs=$($pkg_config --libs $gtkpackage) |
@@ -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 |
@@ -32,6 +32,7 @@ stub-obj-y += trace-control.o | ||
32 | 32 | stub-obj-y += uuid.o |
33 | 33 | stub-obj-y += vm-stop.o |
34 | 34 | stub-obj-y += vmstate.o |
35 | +stub-obj-y += win32-kbd-hook.o | |
35 | 36 | stub-obj-y += fd-register.o |
36 | 37 | stub-obj-y += qmp_memory_device.o |
37 | 38 | stub-obj-y += target-monitor-defs.o |
@@ -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 | +} |
@@ -15,6 +15,9 @@ common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o | ||
15 | 15 | common-obj-$(CONFIG_COCOA) += cocoa.o |
16 | 16 | common-obj-$(CONFIG_VNC) += $(vnc-obj-y) |
17 | 17 | 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 | |
18 | 21 | |
19 | 22 | # ui-sdl module |
20 | 23 | common-obj-$(CONFIG_SDL) += sdl.mo |
@@ -38,6 +38,10 @@ | ||
38 | 38 | |
39 | 39 | #include "ui/console.h" |
40 | 40 | #include "ui/gtk.h" |
41 | +#ifdef G_OS_WIN32 | |
42 | +#include <gdk/gdkwin32.h> | |
43 | +#endif | |
44 | +#include "ui/win32-kbd-hook.h" | |
41 | 45 | |
42 | 46 | #include <glib/gi18n.h> |
43 | 47 | #include <locale.h> |
@@ -108,15 +112,6 @@ | ||
108 | 112 | # define VTE_CHECK_VERSION(a, b, c) 0 |
109 | 113 | #endif |
110 | 114 | |
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 | - | |
120 | 115 | #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK) |
121 | 116 | |
122 | 117 | static const guint16 *keycode_map; |
@@ -173,8 +168,6 @@ struct GtkDisplayState { | ||
173 | 168 | |
174 | 169 | bool external_pause_update; |
175 | 170 | |
176 | - bool ignore_keys; | |
177 | - | |
178 | 171 | DisplayOptions *opts; |
179 | 172 | }; |
180 | 173 |
@@ -428,6 +421,16 @@ static void gd_widget_reparent(GtkWidget *from, GtkWidget *to, | ||
428 | 421 | g_object_unref(G_OBJECT(widget)); |
429 | 422 | } |
430 | 423 | |
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 | + | |
431 | 434 | /** DisplayState Callbacks **/ |
432 | 435 | |
433 | 436 | static void gd_update(DisplayChangeListener *dcl, |
@@ -487,12 +490,7 @@ static void gd_refresh(DisplayChangeListener *dcl) | ||
487 | 490 | |
488 | 491 | static GdkDevice *gd_get_pointer(GdkDisplay *dpy) |
489 | 492 | { |
490 | -#if GTK_CHECK_VERSION(3, 20, 0) | |
491 | 493 | 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 | |
496 | 494 | } |
497 | 495 | |
498 | 496 | static void gd_mouse_set(DisplayChangeListener *dcl, |
@@ -874,27 +872,18 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, | ||
874 | 872 | |
875 | 873 | if (!qemu_input_is_absolute() && s->ptr_owner == vc) { |
876 | 874 | 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; | |
877 | 879 | int screen_width, screen_height; |
878 | 880 | |
879 | 881 | int x = (int)motion->x_root; |
880 | 882 | int y = (int)motion->y_root; |
881 | 883 | |
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; | |
898 | 887 | |
899 | 888 | /* In relative mode check to see if client pointer hit |
900 | 889 | * 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) | ||
1023 | 1012 | #ifdef GDK_WINDOWING_WIN32 |
1024 | 1013 | if (GDK_IS_WIN32_DISPLAY(dpy)) { |
1025 | 1014 | 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; | |
1028 | 1017 | } |
1029 | 1018 | #endif |
1030 | 1019 |
@@ -1070,6 +1059,25 @@ static int gd_map_keycode(int scancode) | ||
1070 | 1059 | return keycode_map[scancode]; |
1071 | 1060 | } |
1072 | 1061 | |
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 | + | |
1073 | 1081 | static gboolean gd_text_key_down(GtkWidget *widget, |
1074 | 1082 | GdkEventKey *key, void *opaque) |
1075 | 1083 | { |
@@ -1081,7 +1089,7 @@ static gboolean gd_text_key_down(GtkWidget *widget, | ||
1081 | 1089 | } else if (key->length) { |
1082 | 1090 | kbd_put_string_console(con, key->string, key->length); |
1083 | 1091 | } else { |
1084 | - int qcode = gd_map_keycode(key->hardware_keycode); | |
1092 | + int qcode = gd_map_keycode(gd_get_keycode(key)); | |
1085 | 1093 | kbd_put_qcode_console(con, qcode, false); |
1086 | 1094 | } |
1087 | 1095 | return TRUE; |
@@ -1090,18 +1098,19 @@ static gboolean gd_text_key_down(GtkWidget *widget, | ||
1090 | 1098 | static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) |
1091 | 1099 | { |
1092 | 1100 | 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; | |
1100 | 1102 | |
1101 | -#ifdef WIN32 | |
1103 | +#ifdef G_OS_WIN32 | |
1102 | 1104 | /* on windows, we ought to ignore the reserved key event? */ |
1103 | 1105 | if (key->hardware_keycode == 0xff) |
1104 | 1106 | 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 | + } | |
1105 | 1114 | #endif |
1106 | 1115 | |
1107 | 1116 | if (key->keyval == GDK_KEY_Pause |
@@ -1117,9 +1126,10 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) | ||
1117 | 1126 | return TRUE; |
1118 | 1127 | } |
1119 | 1128 | |
1120 | - qcode = gd_map_keycode(key->hardware_keycode); | |
1129 | + keycode = gd_get_keycode(key); | |
1130 | + qcode = gd_map_keycode(keycode); | |
1121 | 1131 | |
1122 | - trace_gd_key_event(vc->label, key->hardware_keycode, qcode, | |
1132 | + trace_gd_key_event(vc->label, keycode, qcode, | |
1123 | 1133 | (key->type == GDK_KEY_PRESS) ? "down" : "up"); |
1124 | 1134 | |
1125 | 1135 | qkbd_state_key_event(vc->gfx.kbd, qcode, |
@@ -1128,6 +1138,25 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) | ||
1128 | 1138 | return TRUE; |
1129 | 1139 | } |
1130 | 1140 | |
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 | + | |
1131 | 1160 | static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque) |
1132 | 1161 | { |
1133 | 1162 | if (event->type == GDK_MOTION_NOTIFY) { |
@@ -1180,7 +1209,6 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) | ||
1180 | 1209 | gtk_notebook_set_current_page(nb, page); |
1181 | 1210 | gtk_widget_grab_focus(vc->focus); |
1182 | 1211 | } |
1183 | - s->ignore_keys = false; | |
1184 | 1212 | } |
1185 | 1213 | |
1186 | 1214 | static void gd_accel_switch_vc(void *opaque) |
@@ -1390,7 +1418,6 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) | ||
1390 | 1418 | gd_update_full_redraw(vc); |
1391 | 1419 | } |
1392 | 1420 | |
1393 | -#if GTK_CHECK_VERSION(3, 20, 0) | |
1394 | 1421 | static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr) |
1395 | 1422 | { |
1396 | 1423 | 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) | ||
1414 | 1441 | gdk_seat_ungrab(seat); |
1415 | 1442 | } |
1416 | 1443 | } |
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 | |
1443 | 1444 | |
1444 | 1445 | static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) |
1445 | 1446 | { |
@@ -1451,13 +1452,8 @@ static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) | ||
1451 | 1452 | } |
1452 | 1453 | } |
1453 | 1454 | |
1454 | -#if GTK_CHECK_VERSION(3, 20, 0) | |
1455 | + win32_kbd_set_grab(true); | |
1455 | 1456 | 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 | |
1461 | 1457 | vc->s->kbd_owner = vc; |
1462 | 1458 | gd_update_caption(vc->s); |
1463 | 1459 | trace_gd_grab(vc->label, "kbd", reason); |
@@ -1472,11 +1468,8 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) | ||
1472 | 1468 | } |
1473 | 1469 | s->kbd_owner = NULL; |
1474 | 1470 | |
1475 | -#if GTK_CHECK_VERSION(3, 20, 0) | |
1471 | + win32_kbd_set_grab(false); | |
1476 | 1472 | 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 | |
1480 | 1473 | gd_update_caption(s); |
1481 | 1474 | trace_gd_ungrab(vc->label, "kbd"); |
1482 | 1475 | } |
@@ -1493,21 +1486,9 @@ static void gd_grab_pointer(VirtualConsole *vc, const char *reason) | ||
1493 | 1486 | } |
1494 | 1487 | } |
1495 | 1488 | |
1496 | -#if GTK_CHECK_VERSION(3, 20, 0) | |
1497 | 1489 | gd_grab_update(vc, vc->s->kbd_owner == vc, true); |
1498 | 1490 | gdk_device_get_position(gd_get_pointer(display), |
1499 | 1491 | 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 | |
1511 | 1492 | vc->s->ptr_owner = vc; |
1512 | 1493 | gd_update_caption(vc->s); |
1513 | 1494 | trace_gd_grab(vc->label, "ptr", reason); |
@@ -1524,17 +1505,10 @@ static void gd_ungrab_pointer(GtkDisplayState *s) | ||
1524 | 1505 | s->ptr_owner = NULL; |
1525 | 1506 | |
1526 | 1507 | display = gtk_widget_get_display(vc->gfx.drawing_area); |
1527 | -#if GTK_CHECK_VERSION(3, 20, 0) | |
1528 | 1508 | gd_grab_update(vc, vc->s->kbd_owner == vc, false); |
1529 | 1509 | gdk_device_warp(gd_get_pointer(display), |
1530 | 1510 | gtk_widget_get_screen(vc->gfx.drawing_area), |
1531 | 1511 | 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 | |
1538 | 1512 | gd_update_caption(s); |
1539 | 1513 | trace_gd_ungrab(vc->label, "ptr"); |
1540 | 1514 | } |
@@ -1614,12 +1588,22 @@ static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, | ||
1614 | 1588 | return TRUE; |
1615 | 1589 | } |
1616 | 1590 | |
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 | + | |
1617 | 1600 | static gboolean gd_focus_out_event(GtkWidget *widget, |
1618 | - GdkEventCrossing *crossing, gpointer opaque) | |
1601 | + GdkEventFocus *event, gpointer opaque) | |
1619 | 1602 | { |
1620 | 1603 | VirtualConsole *vc = opaque; |
1621 | 1604 | GtkDisplayState *s = vc->s; |
1622 | 1605 | |
1606 | + win32_kbd_set_window(NULL); | |
1623 | 1607 | gtk_release_modifiers(s); |
1624 | 1608 | return TRUE; |
1625 | 1609 | } |
@@ -1878,10 +1862,14 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) | ||
1878 | 1862 | G_CALLBACK(gd_enter_event), vc); |
1879 | 1863 | g_signal_connect(vc->gfx.drawing_area, "leave-notify-event", |
1880 | 1864 | 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); | |
1881 | 1867 | g_signal_connect(vc->gfx.drawing_area, "focus-out-event", |
1882 | 1868 | G_CALLBACK(gd_focus_out_event), vc); |
1883 | 1869 | g_signal_connect(vc->gfx.drawing_area, "configure-event", |
1884 | 1870 | G_CALLBACK(gd_configure), vc); |
1871 | + g_signal_connect(vc->gfx.drawing_area, "grab-broken-event", | |
1872 | + G_CALLBACK(gd_grab_broken_event), vc); | |
1885 | 1873 | } else { |
1886 | 1874 | g_signal_connect(vc->gfx.drawing_area, "key-press-event", |
1887 | 1875 | G_CALLBACK(gd_text_key_down), vc); |
@@ -27,6 +27,7 @@ | ||
27 | 27 | #include "ui/console.h" |
28 | 28 | #include "ui/input.h" |
29 | 29 | #include "ui/sdl2.h" |
30 | +#include "trace.h" | |
30 | 31 | |
31 | 32 | void sdl2_process_key(struct sdl2_console *scon, |
32 | 33 | SDL_KeyboardEvent *ev) |
@@ -38,6 +39,8 @@ void sdl2_process_key(struct sdl2_console *scon, | ||
38 | 39 | return; |
39 | 40 | } |
40 | 41 | 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"); | |
41 | 44 | qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN); |
42 | 45 | |
43 | 46 | if (!qemu_console_is_graphic(con)) { |
@@ -30,6 +30,7 @@ | ||
30 | 30 | #include "ui/sdl2.h" |
31 | 31 | #include "sysemu/runstate.h" |
32 | 32 | #include "sysemu/sysemu.h" |
33 | +#include "ui/win32-kbd-hook.h" | |
33 | 34 | |
34 | 35 | static int sdl2_num_outputs; |
35 | 36 | static struct sdl2_console *sdl2_console; |
@@ -220,6 +221,7 @@ static void sdl_grab_start(struct sdl2_console *scon) | ||
220 | 221 | } |
221 | 222 | SDL_SetWindowGrab(scon->real_window, SDL_TRUE); |
222 | 223 | gui_grab = 1; |
224 | + win32_kbd_set_grab(true); | |
223 | 225 | sdl_update_caption(scon); |
224 | 226 | } |
225 | 227 |
@@ -227,6 +229,7 @@ static void sdl_grab_end(struct sdl2_console *scon) | ||
227 | 229 | { |
228 | 230 | SDL_SetWindowGrab(scon->real_window, SDL_FALSE); |
229 | 231 | gui_grab = 0; |
232 | + win32_kbd_set_grab(false); | |
230 | 233 | sdl_show_cursor(scon); |
231 | 234 | sdl_update_caption(scon); |
232 | 235 | } |
@@ -325,6 +328,19 @@ static int get_mod_state(void) | ||
325 | 328 | } |
326 | 329 | } |
327 | 330 | |
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 | + | |
328 | 344 | static void handle_keydown(SDL_Event *ev) |
329 | 345 | { |
330 | 346 | int win; |
@@ -544,6 +560,11 @@ static void handle_windowevent(SDL_Event *ev) | ||
544 | 560 | sdl2_redraw(scon); |
545 | 561 | break; |
546 | 562 | 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 */ | |
547 | 568 | case SDL_WINDOWEVENT_ENTER: |
548 | 569 | if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { |
549 | 570 | absolute_mouse_grab(scon); |
@@ -558,6 +579,9 @@ static void handle_windowevent(SDL_Event *ev) | ||
558 | 579 | scon->ignore_hotkeys = get_mod_state(); |
559 | 580 | break; |
560 | 581 | case SDL_WINDOWEVENT_FOCUS_LOST: |
582 | + if (qemu_console_is_graphic(scon->dcl.con)) { | |
583 | + win32_kbd_set_window(NULL); | |
584 | + } | |
561 | 585 | if (gui_grab && !gui_fullscreen) { |
562 | 586 | sdl_grab_end(scon); |
563 | 587 | } |
@@ -857,17 +881,16 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) | ||
857 | 881 | SDL_SetWindowIcon(sdl2_console[0].real_window, icon); |
858 | 882 | } |
859 | 883 | |
860 | - gui_grab = 0; | |
861 | - if (gui_fullscreen) { | |
862 | - sdl_grab_start(0); | |
863 | - } | |
864 | - | |
865 | 884 | mouse_mode_notifier.notify = sdl_mouse_mode_change; |
866 | 885 | qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier); |
867 | 886 | |
868 | 887 | sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); |
869 | 888 | sdl_cursor_normal = SDL_GetCursor(); |
870 | 889 | |
890 | + if (gui_fullscreen) { | |
891 | + sdl_grab_start(&sdl2_console[0]); | |
892 | + } | |
893 | + | |
871 | 894 | atexit(sdl_cleanup); |
872 | 895 | } |
873 | 896 |
@@ -75,6 +75,9 @@ input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value | ||
75 | 75 | input_event_sync(void) "" |
76 | 76 | input_mouse_mode(int absolute) "absolute %d" |
77 | 77 | |
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 | + | |
78 | 81 | # spice-display.c |
79 | 82 | 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" |
80 | 83 | qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u" |
@@ -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 | +} |