@samitouri / QOSamiQemu / commits / 89b76c5fb0

ui/gtk: Use Linux key codes

QemuInputEvent now stores Linux key codes for key events. Use those codes directly instead of translating between internal key code representations. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260520-input-v3-19-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>

Akihiko Odaki committed May 20, 2026 at 15:48 UTC 89b76c5fb07af767076f6749c3516a07d1c783a3
4 files changed +45 -35
ui/gtk.c
+29 -22
@@ -55,6 +55,7 @@
55 #include <math.h>
56
57 #include "trace.h"
58 +#include "standard-headers/linux/input-event-codes.h"
59 #include "ui/input.h"
60 #include "system/runstate.h"
61 #include "system/system.h"
@@ -120,6 +121,7 @@
121
122 static const guint16 *keycode_map;
123 static size_t keycode_maplen;
124 +static bool keycode_xorgevdev;
125
126 struct VCChardev {
127 Chardev parent;
@@ -1211,39 +1213,42 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
1213 return TRUE;
1214 }
1215
1214 -static const guint16 *gd_get_keymap(size_t *maplen)
1216 +static const guint16 *gd_get_keymap(size_t *maplen, bool *xorgevdev)
1217 {
1218 GdkDisplay *dpy = gdk_display_get_default();
1219
1220 + *maplen = 0;
1221 + *xorgevdev = false;
1222 +
1223 #ifdef GDK_WINDOWING_X11
1224 if (GDK_IS_X11_DISPLAY(dpy)) {
1225 trace_gd_keymap_windowing("x11");
1226 return qemu_xkeymap_mapping_table(
1222 - gdk_x11_display_get_xdisplay(dpy), maplen);
1227 + gdk_x11_display_get_xdisplay(dpy), maplen, xorgevdev);
1228 }
1229 #endif
1230
1231 #ifdef GDK_WINDOWING_WAYLAND
1232 if (GDK_IS_WAYLAND_DISPLAY(dpy)) {
1233 trace_gd_keymap_windowing("wayland");
1229 - *maplen = qemu_input_map_xorgevdev_to_qcode_len;
1230 - return qemu_input_map_xorgevdev_to_qcode;
1234 + *xorgevdev = true;
1235 + return NULL;
1236 }
1237 #endif
1238
1239 #ifdef GDK_WINDOWING_WIN32
1240 if (GDK_IS_WIN32_DISPLAY(dpy)) {
1241 trace_gd_keymap_windowing("win32");
1237 - *maplen = qemu_input_map_atset1_to_qcode_len;
1238 - return qemu_input_map_atset1_to_qcode;
1242 + *maplen = qemu_input_map_atset1_to_linux_len;
1243 + return qemu_input_map_atset1_to_linux;
1244 }
1245 #endif
1246
1247 #ifdef GDK_WINDOWING_QUARTZ
1248 if (GDK_IS_QUARTZ_DISPLAY(dpy)) {
1249 trace_gd_keymap_windowing("quartz");
1245 - *maplen = qemu_input_map_osx_to_qcode_len;
1246 - return qemu_input_map_osx_to_qcode;
1250 + *maplen = qemu_input_map_osx_to_linux_len;
1251 + return qemu_input_map_osx_to_linux;
1252 }
1253 #endif
1254
@@ -1253,8 +1258,8 @@ static const guint16 *gd_get_keymap(size_t *maplen)
1258 g_warning("experimental: using broadway, x11 virtual keysym\n"
1259 "mapping - with very limited support. See also\n"
1260 "https://bugzilla.gnome.org/show_bug.cgi?id=700105");
1256 - *maplen = qemu_input_map_x11_to_qcode_len;
1257 - return qemu_input_map_x11_to_qcode;
1261 + *maplen = qemu_input_map_x11_to_linux_len;
1262 + return qemu_input_map_x11_to_linux;
1263 }
1264 #endif
1265
@@ -1269,8 +1274,11 @@ static const guint16 *gd_get_keymap(size_t *maplen)
1274 }
1275
1276
1272 -static int gd_map_keycode(int scancode)
1277 +static unsigned int gd_map_keycode(int scancode)
1278 {
1279 + if (keycode_xorgevdev) {
1280 + return scancode < 8 ? KEY_RESERVED : scancode - 8;
1281 + }
1282 if (!keycode_map) {
1283 return 0;
1284 }
@@ -1307,12 +1315,12 @@ static gboolean gd_text_key_down(GtkWidget *widget,
1315 QemuTextConsole *con = QEMU_TEXT_CONSOLE(vc->gfx.dcl.con);
1316
1317 if (key->keyval == GDK_KEY_Delete) {
1310 - qemu_text_console_put_qcode(con, Q_KEY_CODE_DELETE, false);
1318 + qemu_text_console_put_linux(con, KEY_DELETE, false);
1319 } else if (key->length) {
1320 qemu_text_console_put_string(con, key->string, key->length);
1321 } else {
1314 - int qcode = gd_map_keycode(gd_get_keycode(key));
1315 - qemu_text_console_put_qcode(con, qcode, false);
1322 + unsigned int lnx = gd_map_keycode(gd_get_keycode(key));
1323 + qemu_text_console_put_linux(con, lnx, false);
1324 }
1325 return TRUE;
1326 }
@@ -1320,7 +1328,8 @@ static gboolean gd_text_key_down(GtkWidget *widget,
1328 static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
1329 {
1330 VirtualConsole *vc = opaque;
1323 - int keycode, qcode;
1331 + int keycode;
1332 + unsigned int lnx;
1333
1334 #ifdef G_OS_WIN32
1335 /* on windows, we ought to ignore the reserved key event? */
@@ -1343,20 +1352,18 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
1352 || key->hardware_keycode == VK_PAUSE
1353 #endif
1354 ) {
1346 - qkbd_state_key_event(vc->gfx.kbd,
1347 - qemu_input_map_qcode_to_linux[Q_KEY_CODE_PAUSE],
1355 + qkbd_state_key_event(vc->gfx.kbd, KEY_PAUSE,
1356 key->type == GDK_KEY_PRESS);
1357 return TRUE;
1358 }
1359
1360 keycode = gd_get_keycode(key);
1353 - qcode = gd_map_keycode(keycode);
1361 + lnx = gd_map_keycode(keycode);
1362
1355 - trace_gd_key_event(vc->label, keycode, qemu_input_map_qcode_to_linux[qcode],
1363 + trace_gd_key_event(vc->label, keycode, lnx,
1364 (key->type == GDK_KEY_PRESS) ? "down" : "up");
1365
1358 - qkbd_state_key_event(vc->gfx.kbd, qemu_input_map_qcode_to_linux[qcode],
1359 - key->type == GDK_KEY_PRESS);
1366 + qkbd_state_key_event(vc->gfx.kbd, lnx, key->type == GDK_KEY_PRESS);
1367
1368 return TRUE;
1369 }
@@ -2660,7 +2667,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
2667 #endif
2668 }
2669
2663 - keycode_map = gd_get_keymap(&keycode_maplen);
2670 + keycode_map = gd_get_keymap(&keycode_maplen, &keycode_xorgevdev);
2671
2672 #if defined(CONFIG_VTE)
2673 type_register_static(&char_gd_vc_type_info);
ui/trace-events
+1 -1
@@ -22,7 +22,7 @@ ppm_save(int fd, void *image) "fd=%d image=%p"
22 # gtk.c
23 gd_switch(const char *tab, int width, int height) "tab=%s, width=%d, height=%d"
24 gd_update(const char *tab, int x, int y, int w, int h) "tab=%s, x=%d, y=%d, w=%d, h=%d"
25 -gd_key_event(const char *tab, int gdk_keycode, int qkeycode, const char *action) "tab=%s, translated GDK keycode %d to QKeyCode %d (%s)"
25 +gd_key_event(const char *tab, int gdk_keycode, unsigned int lnx, const char *action) "tab=%s, translated GDK keycode %d to Linux %u (%s)"
26 gd_grab(const char *tab, const char *device, const char *reason) "tab=%s, dev=%s, reason=%s"
27 gd_ungrab(const char *tab, const char *device) "tab=%s, dev=%s"
28 gd_keymap_windowing(const char *name) "backend=%s"
ui/x_keymap.c
+13 -11
@@ -52,11 +52,12 @@ static gboolean check_for_xquartz(Display *dpy)
52 return match;
53 }
54
55 -const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen)
55 +const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen,
56 + bool *evdev)
57 {
58 XkbDescPtr desc;
59 const gchar *keycodes = NULL;
59 - const guint16 *map;
60 + const guint16 *map = NULL;
61
62 /* There is no easy way to determine what X11 server
63 * and platform & keyboard driver is in use. Thus we
@@ -81,24 +82,26 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen)
82 XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
83 }
84
85 + *maplen = 0;
86 + *evdev = false;
87 +
88 if (check_for_xwin(dpy)) {
89 trace_xkeymap_keymap("xwin");
86 - *maplen = qemu_input_map_xorgxwin_to_qcode_len;
87 - map = qemu_input_map_xorgxwin_to_qcode;
90 + *maplen = qemu_input_map_xorgxwin_to_linux_len;
91 + map = qemu_input_map_xorgxwin_to_linux;
92 } else if (check_for_xquartz(dpy)) {
93 trace_xkeymap_keymap("xquartz");
90 - *maplen = qemu_input_map_xorgxquartz_to_qcode_len;
91 - map = qemu_input_map_xorgxquartz_to_qcode;
94 + *maplen = qemu_input_map_xorgxquartz_to_linux_len;
95 + map = qemu_input_map_xorgxquartz_to_linux;
96 } else if ((keycodes && g_str_has_prefix(keycodes, "evdev")) ||
97 (XKeysymToKeycode(dpy, XK_Page_Up) == 0x70)) {
98 trace_xkeymap_keymap("evdev");
95 - *maplen = qemu_input_map_xorgevdev_to_qcode_len;
96 - map = qemu_input_map_xorgevdev_to_qcode;
99 + *evdev = true;
100 } else if ((keycodes && g_str_has_prefix(keycodes, "xfree86")) ||
101 (XKeysymToKeycode(dpy, XK_Page_Up) == 0x63)) {
102 trace_xkeymap_keymap("kbd");
100 - *maplen = qemu_input_map_xorgkbd_to_qcode_len;
101 - map = qemu_input_map_xorgkbd_to_qcode;
103 + *maplen = qemu_input_map_xorgkbd_to_linux_len;
104 + map = qemu_input_map_xorgkbd_to_linux;
105 } else {
106 trace_xkeymap_keymap("NULL");
107 g_warning("Unknown X11 keycode mapping '%s'.\n"
@@ -110,7 +113,6 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen)
113 " - xprop -root\n"
114 " - xdpyinfo\n",
115 keycodes ? keycodes : "<null>");
113 - map = NULL;
116 }
117 if (keycodes) {
118 XFree((void *)keycodes);
ui/x_keymap.h
+2 -1
@@ -27,6 +27,7 @@
27
28 #include <X11/Xlib.h>
29
30 -const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen);
30 +const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen,
31 + bool *evdev);
32
33 #endif