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);