@samitouri / QOSamiQemu / commits / 9c6833808a

ui/kbd-state: 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-7-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>

Akihiko Odaki committed May 20, 2026 at 15:47 UTC 9c6833808a2a82fdb50e02138760a25f4e075241
8 files changed +108 -59
include/ui/kbd-state.h
+7 -5
@@ -52,11 +52,13 @@ void qkbd_state_free(QKbdState *kbd);
52 * This function takes care to not send suspious events (keyup event
53 * for a key not pressed for example).
54 *
55 + * This function drops events with key codes outside the defined range.
56 + *
57 * @kbd: state tracker state.
56 - * @qcode: the key pressed or released.
58 + * @lnx: the key pressed or released.
59 * @down: true for key down events, false otherwise.
60 */
59 -void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down);
61 +void qkbd_state_key_event(QKbdState *kbd, unsigned int lnx, bool down);
62
63 /**
64 * qkbd_state_set_delay: set key press delay.
@@ -72,12 +74,12 @@ void qkbd_state_set_delay(QKbdState *kbd, int delay_ms);
74 /**
75 * qkbd_state_key_get: get key state.
76 *
75 - * Returns true when the key is down.
77 + * Returns true when the key code is in the defined range and the key is down.
78 *
79 * @kbd: state tracker state.
78 - * @qcode: the key to query.
80 + * @lnx: the key to query.
81 */
80 -bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode);
82 +bool qkbd_state_key_get(QKbdState *kbd, unsigned int lnx);
83
84 /**
85 * qkbd_state_modifier_get: get modifier state.
ui/cocoa.m
+50 -17
@@ -767,7 +767,8 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
767 }
768
769 - (void) toggleKey: (int)keycode {
770 - qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode));
770 + unsigned int lnx = qemu_input_map_qcode_to_linux[keycode];
771 + qkbd_state_key_event(kbd, lnx, !qkbd_state_key_get(kbd, lnx));
772 }
773
774 // Does the work of sending input to the monitor
@@ -889,34 +890,62 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
890 */
891 if (!!(modifiers & NSEventModifierFlagCapsLock) !=
892 qkbd_state_modifier_get(kbd, QKBD_MOD_CAPSLOCK)) {
892 - qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, true);
893 - qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, false);
893 + qkbd_state_key_event(kbd,
894 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_CAPS_LOCK],
895 + true);
896 + qkbd_state_key_event(kbd,
897 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_CAPS_LOCK],
898 + false);
899 }
900
901 if (!(modifiers & NSEventModifierFlagShift)) {
897 - qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT, false);
898 - qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT_R, false);
902 + qkbd_state_key_event(kbd,
903 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_SHIFT],
904 + false);
905 + qkbd_state_key_event(kbd,
906 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_SHIFT_R],
907 + false);
908 }
909 if (!(modifiers & NSEventModifierFlagControl)) {
901 - qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL, false);
902 - qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL_R, false);
910 + qkbd_state_key_event(kbd,
911 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_CTRL],
912 + false);
913 + qkbd_state_key_event(kbd,
914 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_CTRL_R],
915 + false);
916 }
917 if (!(modifiers & NSEventModifierFlagOption)) {
918 if (swap_opt_cmd) {
906 - qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
907 - qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
919 + qkbd_state_key_event(kbd,
920 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_L],
921 + false);
922 + qkbd_state_key_event(kbd,
923 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_R],
924 + false);
925 } else {
909 - qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
910 - qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
926 + qkbd_state_key_event(kbd,
927 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT],
928 + false);
929 + qkbd_state_key_event(kbd,
930 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT_R],
931 + false);
932 }
933 }
934 if (!(modifiers & NSEventModifierFlagCommand)) {
935 if (swap_opt_cmd) {
915 - qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
916 - qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
936 + qkbd_state_key_event(kbd,
937 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT],
938 + false);
939 + qkbd_state_key_event(kbd,
940 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT_R],
941 + false);
942 } else {
918 - qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
919 - qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
943 + qkbd_state_key_event(kbd,
944 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_L],
945 + false);
946 + qkbd_state_key_event(kbd,
947 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_R],
948 + false);
949 }
950 }
951
@@ -1023,7 +1052,9 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
1052 }
1053
1054 if (qemu_console_is_graphic(dcl.con)) {
1026 - qkbd_state_key_event(kbd, keycode, true);
1055 + qkbd_state_key_event(kbd,
1056 + qemu_input_map_qcode_to_linux[keycode],
1057 + true);
1058 } else {
1059 [self handleMonitorInput: event];
1060 }
@@ -1038,7 +1069,9 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
1069 }
1070
1071 if (qemu_console_is_graphic(dcl.con)) {
1041 - qkbd_state_key_event(kbd, keycode, false);
1072 + qkbd_state_key_event(kbd,
1073 + qemu_input_map_qcode_to_linux[keycode],
1074 + false);
1075 }
1076 return true;
1077 case NSEventTypeScrollWheel:
ui/dbus-console.c
+2 -2
@@ -343,7 +343,7 @@ dbus_kbd_press(DBusDisplayConsole *ddc,
343
344 trace_dbus_kbd_press(arg_keycode);
345
346 - qkbd_state_key_event(ddc->kbd, qcode, true);
346 + qkbd_state_key_event(ddc->kbd, qemu_input_map_qcode_to_linux[qcode], true);
347
348 qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation);
349
@@ -359,7 +359,7 @@ dbus_kbd_release(DBusDisplayConsole *ddc,
359
360 trace_dbus_kbd_release(arg_keycode);
361
362 - qkbd_state_key_event(ddc->kbd, qcode, false);
362 + qkbd_state_key_event(ddc->kbd, qemu_input_map_qcode_to_linux[qcode], false);
363
364 qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation);
365
ui/gtk.c
+4 -3
@@ -1343,7 +1343,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
1343 || key->hardware_keycode == VK_PAUSE
1344 #endif
1345 ) {
1346 - qkbd_state_key_event(vc->gfx.kbd, Q_KEY_CODE_PAUSE,
1346 + qkbd_state_key_event(vc->gfx.kbd,
1347 + qemu_input_map_qcode_to_linux[Q_KEY_CODE_PAUSE],
1348 key->type == GDK_KEY_PRESS);
1349 return TRUE;
1350 }
@@ -1351,10 +1352,10 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
1352 keycode = gd_get_keycode(key);
1353 qcode = gd_map_keycode(keycode);
1354
1354 - trace_gd_key_event(vc->label, keycode, qcode,
1355 + trace_gd_key_event(vc->label, keycode, qemu_input_map_qcode_to_linux[qcode],
1356 (key->type == GDK_KEY_PRESS) ? "down" : "up");
1357
1357 - qkbd_state_key_event(vc->gfx.kbd, qcode,
1358 + qkbd_state_key_event(vc->gfx.kbd, qemu_input_map_qcode_to_linux[qcode],
1359 key->type == GDK_KEY_PRESS);
1360
1361 return TRUE;
ui/kbd-state.c
+34 -27
@@ -5,6 +5,7 @@
5 */
6 #include "qemu/osdep.h"
7 #include "qemu/bitmap.h"
8 +#include "standard-headers/linux/input-event-codes.h"
9 #include "ui/console.h"
10 #include "ui/input.h"
11 #include "ui/kbd-state.h"
@@ -12,15 +13,15 @@
13 struct QKbdState {
14 QemuConsole *con;
15 int key_delay_ms;
15 - DECLARE_BITMAP(keys, Q_KEY_CODE__MAX);
16 + DECLARE_BITMAP(keys, KEY_CNT);
17 DECLARE_BITMAP(mods, QKBD_MOD__MAX);
18 };
19
20 static void qkbd_state_modifier_update(QKbdState *kbd,
20 - QKeyCode qcode1, QKeyCode qcode2,
21 + unsigned int lnx1, unsigned int lnx2,
22 QKbdModifier mod)
23 {
23 - if (test_bit(qcode1, kbd->keys) || test_bit(qcode2, kbd->keys)) {
24 + if (test_bit(lnx1, kbd->keys) || test_bit(lnx2, kbd->keys)) {
25 set_bit(mod, kbd->mods);
26 } else {
27 clear_bit(mod, kbd->mods);
@@ -32,14 +33,20 @@ bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod)
33 return test_bit(mod, kbd->mods);
34 }
35
35 -bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode)
36 +bool qkbd_state_key_get(QKbdState *kbd, unsigned int lnx)
37 {
37 - return test_bit(qcode, kbd->keys);
38 + return lnx < KEY_CNT && test_bit(lnx, kbd->keys);
39 }
40
40 -void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
41 +void qkbd_state_key_event(QKbdState *kbd, unsigned int lnx, bool down)
42 {
42 - bool state = test_bit(qcode, kbd->keys);
43 + bool state;
44 +
45 + if (lnx >= KEY_CNT) {
46 + return;
47 + }
48 +
49 + state = test_bit(lnx, kbd->keys);
50
51 if (down == false /* got key-up event */ &&
52 state == false /* key is not pressed */) {
@@ -59,35 +66,35 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
66
67 /* update key and modifier state */
68 if (down) {
62 - set_bit(qcode, kbd->keys);
69 + set_bit(lnx, kbd->keys);
70 } else {
64 - clear_bit(qcode, kbd->keys);
71 + clear_bit(lnx, kbd->keys);
72 }
66 - switch (qcode) {
67 - case Q_KEY_CODE_SHIFT:
68 - case Q_KEY_CODE_SHIFT_R:
69 - qkbd_state_modifier_update(kbd, Q_KEY_CODE_SHIFT, Q_KEY_CODE_SHIFT_R,
73 + switch (lnx) {
74 + case KEY_LEFTSHIFT:
75 + case KEY_RIGHTSHIFT:
76 + qkbd_state_modifier_update(kbd, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
77 QKBD_MOD_SHIFT);
78 break;
72 - case Q_KEY_CODE_CTRL:
73 - case Q_KEY_CODE_CTRL_R:
74 - qkbd_state_modifier_update(kbd, Q_KEY_CODE_CTRL, Q_KEY_CODE_CTRL_R,
79 + case KEY_LEFTCTRL:
80 + case KEY_RIGHTCTRL:
81 + qkbd_state_modifier_update(kbd, KEY_LEFTCTRL, KEY_RIGHTCTRL,
82 QKBD_MOD_CTRL);
83 break;
77 - case Q_KEY_CODE_ALT:
78 - qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT, Q_KEY_CODE_ALT,
84 + case KEY_LEFTALT:
85 + qkbd_state_modifier_update(kbd, KEY_LEFTALT, KEY_LEFTALT,
86 QKBD_MOD_ALT);
87 break;
81 - case Q_KEY_CODE_ALT_R:
82 - qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT_R, Q_KEY_CODE_ALT_R,
88 + case KEY_RIGHTALT:
89 + qkbd_state_modifier_update(kbd, KEY_RIGHTALT, KEY_RIGHTALT,
90 QKBD_MOD_ALTGR);
91 break;
85 - case Q_KEY_CODE_CAPS_LOCK:
92 + case KEY_CAPSLOCK:
93 if (down) {
94 change_bit(QKBD_MOD_CAPSLOCK, kbd->mods);
95 }
96 break;
90 - case Q_KEY_CODE_NUM_LOCK:
97 + case KEY_NUMLOCK:
98 if (down) {
99 change_bit(QKBD_MOD_NUMLOCK, kbd->mods);
100 }
@@ -99,7 +106,7 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
106
107 /* send to guest */
108 if (qemu_console_is_graphic(kbd->con)) {
102 - qemu_input_event_send_key_qcode(kbd->con, qcode, down);
109 + qemu_input_event_send_key_linux(kbd->con, lnx, down);
110 if (kbd->key_delay_ms) {
111 qemu_input_event_send_key_delay(kbd->key_delay_ms);
112 }
@@ -108,11 +115,11 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
115
116 void qkbd_state_lift_all_keys(QKbdState *kbd)
117 {
111 - int qcode;
118 + unsigned int lnx;
119
113 - for (qcode = 0; qcode < Q_KEY_CODE__MAX; qcode++) {
114 - if (test_bit(qcode, kbd->keys)) {
115 - qkbd_state_key_event(kbd, qcode, false);
120 + for (lnx = 0; lnx < KEY_CNT; lnx++) {
121 + if (test_bit(lnx, kbd->keys)) {
122 + qkbd_state_key_event(kbd, lnx, false);
123 }
124 }
125 }
ui/keymaps.c
+2 -1
@@ -257,7 +257,8 @@ int keysym2scancode(kbd_layout_t *k, int keysym,
257 for (i = 0; i < keysym2code->count; i++) {
258 QKeyCode qcode = qemu_input_key_number_to_qcode
259 (keysym2code->keycodes[i]);
260 - if (kbd && qkbd_state_key_get(kbd, qcode)) {
260 + unsigned int lnx = qemu_input_map_qcode_to_linux[qcode];
261 + if (kbd && qkbd_state_key_get(kbd, lnx)) {
262 return keysym2code->keycodes[i];
263 }
264 }
ui/sdl2-input.c
+2 -1
@@ -41,7 +41,8 @@ void sdl2_process_key(struct sdl2_console *scon,
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");
44 - qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN);
44 + qkbd_state_key_event(scon->kbd, qemu_input_map_qcode_to_linux[qcode],
45 + ev->type == SDL_KEYDOWN);
46
47 if (QEMU_IS_TEXT_CONSOLE(con)) {
48 QemuTextConsole *s = QEMU_TEXT_CONSOLE(con);
ui/vnc.c
+7 -3
@@ -1799,8 +1799,11 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
1799
1800 static void press_key(VncState *vs, QKeyCode qcode)
1801 {
1802 - qkbd_state_key_event(vs->vd->kbd, qcode, true);
1803 - qkbd_state_key_event(vs->vd->kbd, qcode, false);
1802 + qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
1803 + true);
1804 +
1805 + qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
1806 + false);
1807 }
1808
1809 static void vnc_led_state_change(VncState *vs)
@@ -1907,7 +1910,8 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
1910 }
1911 }
1912
1910 - qkbd_state_key_event(vs->vd->kbd, qcode, down);
1913 + qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
1914 + down);
1915 if (QEMU_IS_TEXT_CONSOLE(vs->vd->dcl.con)) {
1916 QemuTextConsole *con = QEMU_TEXT_CONSOLE(vs->vd->dcl.con);
1917 bool numlock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK);