All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL v3 00/38] Ui patches
@ 2026-05-25  6:31 marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 01/38] ui/vt100: Standardize on uint8_t for "ch" byte variables marcandre.lureau
                   ` (34 more replies)
  0 siblings, 35 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The following changes since commit cbf877d67a812be17a9ce404a589e1bdf722c1f6:

  Merge tag 'pbouvier/pr/docs-20260522' of https://gitlab.com/p-b-o/qemu into staging (2026-05-24 07:45:19 -0400)

are available in the Git repository at:

  https://gitlab.com/marcandre.lureau/qemu.git tags/ui-pull-request

for you to fetch changes up to 7385a3275128fae7ee3de341e9af24a0dd8f7533:

  ui/gtk: Fix focus loss on re-attachment with single VC (2026-05-25 02:01:35 +0400)

----------------------------------------------------------------
 UI pull request

- ui/input: Decouple internal and QAPI input events
- VNC OOB fixes
- vt100 fixes
- GTK focus fix

----------------------------------------------------------------

Akihiko Odaki (29):
  ui/input: Introduce QemuInputEvent typedef
  ui/input: Remove QAPI wrappers from QemuInputEvent
  ui/input: Store QKeyCode directly in QemuInputKeyEvent
  ui/input: Use Linux key codes for internal key events
  ui/input: Prohibit sending KEY_RESERVED
  ui/console: Add qemu_text_console_put_linux()
  ui/kbd-state: Use Linux key codes
  hw/arm/musicpal: Use Linux key codes
  hw/char/escc: Use Linux key codes
  hw/display/xenfb: Use Linux key codes
  hw/input/adb-kbd: Use Linux key codes
  hw/input/hid: Use Linux key codes
  hw/input/ps2: Use Linux key codes
  hw/input/virtio-input: Use Linux key codes
  hw/m68k/next-kbd: Use Linux key codes
  replay: Use Linux key codes
  ui/cocoa: Use Linux key codes
  ui/dbus: Use Linux key codes
  ui/gtk: Use Linux key codes
  ui/input-barrier: Use Linux key codes
  ui/input-legacy: Use Linux key codes
  ui/input-linux: Use Linux key codes
  ui/keymaps: Use Linux key codes
  ui/sdl2: Use Linux key codes
  ui/spice: Use Linux key codes
  ui/vnc: Use Linux key codes
  qemu-keymap: Use Linux key codes
  ui/console: Remove qemu_text_console_put_qcode()
  ui/input: Remove unused QKeyCode helpers and keymaps

Daniel P. Berrangé (4):
  ui/vnc: fix OOB read access in VNC SASL mechname array
  ui/vnc: fix OOB write in VNC stats array
  ui/vnc: fix OOB write in lossy rect worker code
  ui/vnc: fix OOB read updating VNC update frequency stats

Dongwon Kim (1):
  ui/gtk: Fix focus loss on re-attachment with single VC

Heechan Kang (1):
  ui: fix validation of VNC extended clipboard data length

Marc-André Lureau (1):
  ui/vt100: add vt100_fini() check

Peter Maydell (2):
  ui/vt100: Standardize on uint8_t for "ch" byte variables
  ui/vt100: Take byte as uint8_t in bh_utf8_decode()

 include/qemu/typedefs.h      |   1 +
 include/system/replay.h      |   2 +-
 include/ui/console.h         |   3 +-
 include/ui/input.h           |  92 ++++++-----
 include/ui/kbd-state.h       |  12 +-
 replay/replay-internal.h     |   6 +-
 ui/vnc.h                     |   4 +-
 ui/x_keymap.h                |   3 +-
 chardev/msmouse.c            |  12 +-
 chardev/wctablet.c           |  10 +-
 hw/arm/musicpal.c            |  31 ++--
 hw/char/escc.c               |  45 +++---
 hw/display/xenfb.c           |  51 ++-----
 hw/input/adb-kbd.c           | 246 +++++++++++++++--------------
 hw/input/adb-mouse.c         |  22 ++-
 hw/input/hid.c               |  41 +++--
 hw/input/ps2.c               | 118 +++++++-------
 hw/input/stellaris_gamepad.c |  11 +-
 hw/input/virtio-input-hid.c  |  89 ++++++-----
 hw/m68k/next-kbd.c           | 128 ++++++++--------
 qemu-keymap.c                |  41 +++--
 replay/replay-events.c       |   6 +-
 replay/replay-input.c        | 117 +++++---------
 replay/replay.c              |   2 +-
 replay/stubs-system.c        |   2 +-
 tools/qemu-vnc/input.c       |   9 +-
 ui/console.c                 |  62 +++++---
 ui/dbus-console.c            |   8 +-
 ui/gtk.c                     |  55 ++++---
 ui/input-barrier.c           |  26 ++--
 ui/input-keymap.c            |  74 +++++----
 ui/input-legacy.c            |  47 ++----
 ui/input-linux.c             |   3 +-
 ui/input.c                   | 214 ++++++++++++--------------
 ui/kbd-state.c               |  61 ++++----
 ui/keymaps.c                 |   4 +-
 ui/sdl2-input.c              |  17 ++-
 ui/spice-input.c             |   3 +-
 ui/vdagent.c                 |  20 +--
 ui/vnc-auth-sasl.c           |   2 +
 ui/vnc-clipboard.c           |   9 +-
 ui/vnc.c                     |  41 ++---
 ui/vt100.c                   |  11 +-
 ui/x_keymap.c                |  24 +--
 hw/input/trace-events        |   2 +-
 scripts/replay-dump.py       |   8 +-
 tools/qemu-vnc/trace-events  |   2 +-
 ui/cocoa.m                   | 289 ++++++++++++++++++-----------------
 ui/meson.build               |  29 ++--
 ui/trace-events              |   5 +-
 50 files changed, 1021 insertions(+), 1099 deletions(-)

-- 
2.54.0



^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PULL v3 01/38] ui/vt100: Standardize on uint8_t for "ch" byte variables
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 02/38] ui/vt100: Take byte as uint8_t in bh_utf8_decode() marcandre.lureau
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Peter Maydell, Marc-André Lureau

From: Peter Maydell <peter.maydell@linaro.org>

The vt100 code is rather confused about how it handles bytes of data
to be sent to the terminal:
 * vt100_input() takes a buffer of uint8_t
 * each byte is passed to vt100_putchar(), which takes "int ch"
 * that calls vt100_put_one(), which also takes "int ch"
 * vt100_put_one() sets TextCell::ch, which is uint8_t again
 * various places pass the TextCell:ch value to vt100_putcharxy(),
   which takes "int ch" again, but uses it unchecked as an
   index into a 256-entry array

This confuses Coverity (e.g. CID 1659590) and the reader, who may be
unsure whether the "int" variable really does hold only valid byte
values 0..255 and whether we need to bounds-check before doing array
dereferences.

Standardize on keeping known-byte data in uint8_t all the way
through.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20260512104210.3330835-2-peter.maydell@linaro.org>
---
 ui/vt100.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ui/vt100.c b/ui/vt100.c
index e2fba822523..7e373766bc1 100644
--- a/ui/vt100.c
+++ b/ui/vt100.c
@@ -61,7 +61,7 @@ static void image_bitblt(pixman_image_t *image,
                            xs, ys, 0, 0, xd, yd, w, h);
 }
 
-static void vt100_putcharxy(QemuVT100 *vt, int x, int y, int ch,
+static void vt100_putcharxy(QemuVT100 *vt, int x, int y, uint8_t ch,
                             TextAttributes *t_attrib)
 {
     static pixman_image_t *glyphs[256];
@@ -468,7 +468,7 @@ static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
     return *state;
 }
 
-static void vt100_put_one(QemuVT100 *vt, int ch)
+static void vt100_put_one(QemuVT100 *vt, uint8_t ch)
 {
     TextCell *c;
     int y1;
@@ -606,7 +606,7 @@ static void vt100_restore_cursor(QemuVT100 *vt)
     vt->t_attrib = vt->t_attrib_saved;
 }
 
-static void vt100_putchar(QemuVT100 *vt, int ch)
+static void vt100_putchar(QemuVT100 *vt, uint8_t ch)
 {
     int i;
     int x, y;
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 02/38] ui/vt100: Take byte as uint8_t in bh_utf8_decode()
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 01/38] ui/vt100: Standardize on uint8_t for "ch" byte variables marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 03/38] ui/vt100: add vt100_fini() check marcandre.lureau
                   ` (32 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Peter Maydell, Marc-André Lureau

From: Peter Maydell <peter.maydell@linaro.org>

The bh_utf8_decode() UTF8 decoder takes its next byte as a "uint32_t
byte" parameter, but it assumes it to be in bounds as it immediately
indexes into its array with it.

Use "uint8_t" as the argument type instead. This moves us away from
the upstream implementation slightly, but it is the same type as
we use in the one callsite, and it makes it clear that we can't
be indexing off the end of the array with this guest-derived data.

This probably helps make Coverity a bit happier (CID 1659590).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20260512104210.3330835-3-peter.maydell@linaro.org>
---
 ui/vt100.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ui/vt100.c b/ui/vt100.c
index 7e373766bc1..f8140cfa85c 100644
--- a/ui/vt100.c
+++ b/ui/vt100.c
@@ -438,7 +438,7 @@ static void vt100_clear_xy(QemuVT100 *vt, int x, int y)
 #define BH_UTF8_ACCEPT 0
 #define BH_UTF8_REJECT 12
 
-static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
+static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint8_t byte)
 {
     static const uint8_t utf8d[] = {
         /* character class lookup */
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 03/38] ui/vt100: add vt100_fini() check
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 01/38] ui/vt100: Standardize on uint8_t for "ch" byte variables marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 02/38] ui/vt100: Take byte as uint8_t in bh_utf8_decode() marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 04/38] ui/vnc: fix OOB read access in VNC SASL mechname array marcandre.lureau
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

vt100_fini() is called unconditonally from qemu_text_console_finalize(),
but it may not have been vt100_init()/opened: fix the crash in that case.

Fixes: 8fa294482eb ("ui/console-vc: move VT100 state machine ...")
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 ui/vt100.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ui/vt100.c b/ui/vt100.c
index f8140cfa85c..6e64845b6c0 100644
--- a/ui/vt100.c
+++ b/ui/vt100.c
@@ -978,6 +978,9 @@ void vt100_init(QemuVT100 *vt,
 
 void vt100_fini(QemuVT100 *vt)
 {
+    if (!QTAILQ_IN_USE(vt, list)) {
+        return;
+    }
     QTAILQ_REMOVE(&vt100s, vt, list);
     fifo8_destroy(&vt->out_fifo);
     g_free(vt->cells);
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 04/38] ui/vnc: fix OOB read access in VNC SASL mechname array
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (2 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 03/38] ui/vt100: add vt100_fini() check marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 05/38] ui/vnc: fix OOB write in VNC stats array marcandre.lureau
                   ` (30 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Daniel P. Berrangé, Marc-André Lureau

From: Daniel P. Berrangé <berrange@redhat.com>

When reading the SASL mechname array off the VNC connection, if
malicious, the received data may contain embedded NULs. If this
happens the memory buffer returned by g_strndup may be shorter
than the original data. Unfortunately the code continued to
index into this buffer with an offset equal to the original
length. This is a potential OOB read of the array.

Fixes: 5847d9e1 (ui/vnc: simplify and avoid strncpy)
Reported-by: boy juju <agx1657748706@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20260521103353.1645561-2-berrange@redhat.com>
---
 ui/vnc-auth-sasl.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 9964b969ac2..298c8f3769f 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -489,6 +489,8 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_
     char *mechname = g_strndup((const char *) data, len);
     trace_vnc_auth_sasl_mech_choose(vs, mechname);
 
+    /* If 'data' had embedded NUL the dup'd string might now be shorter */
+    len = strlen(mechname);
     if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
         if (vs->sasl.mechlist[len] != '\0' &&
             vs->sasl.mechlist[len] != ',') {
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 05/38] ui/vnc: fix OOB write in VNC stats array
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (3 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 04/38] ui/vnc: fix OOB read access in VNC SASL mechname array marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 06/38] ui/vnc: fix OOB write in lossy rect worker code marcandre.lureau
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Daniel P. Berrangé, Marc-André Lureau

From: Daniel P. Berrangé <berrange@redhat.com>

The VncSurface struct maintains update statistics in an array:

    VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];

where the dimensions are defined as:

  #define VNC_STAT_RECT  64
  #define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT)
  #define VNC_STAT_ROWS (VNC_MAX_HEIGHT / VNC_STAT_RECT)

If VNC_MAX_WIDTH / VNC_MAX_HEIGHT are not an exact multiple of
VNC_STAT_REC, the COLS/ROWS will be undersized by 1.

Unfortunately:

  #define VNC_MAX_HEIGHT 2160

is not a multiple of 64, so there is potential for OOB reads and
writes in the 'stats' array, if the guest surface is over 2112
pixels in height. An array overflow occurs when vnc_update_stats()
records new statistics, either scribbling over data later in the
VncDisplay struct that 'stats' is embedded in, or performing an
OOB write on the allocated struct memory.

Fixes: CVE-2026-48002
Reported-by: boy juju <agx1657748706@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20260521103353.1645561-3-berrange@redhat.com>
---
 ui/vnc.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ui/vnc.h b/ui/vnc.h
index 0750bf5f72f..c8d87cd5301 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -85,8 +85,8 @@ typedef void VncSendHextileTile(VncState *vs,
 #define VNC_DIRTY_BPL(x) (sizeof((x)->dirty) / VNC_MAX_HEIGHT * BITS_PER_BYTE)
 
 #define VNC_STAT_RECT  64
-#define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT)
-#define VNC_STAT_ROWS (VNC_MAX_HEIGHT / VNC_STAT_RECT)
+#define VNC_STAT_COLS DIV_ROUND_UP(VNC_MAX_WIDTH, VNC_STAT_RECT)
+#define VNC_STAT_ROWS DIV_ROUND_UP(VNC_MAX_HEIGHT, VNC_STAT_RECT)
 
 #define VNC_AUTH_CHALLENGE_SIZE 16
 
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 06/38] ui/vnc: fix OOB write in lossy rect worker code
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (4 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 05/38] ui/vnc: fix OOB write in VNC stats array marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 07/38] ui/vnc: fix OOB read updating VNC update frequency stats marcandre.lureau
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Daniel P. Berrangé, Marc-André Lureau

From: Daniel P. Berrangé <berrange@redhat.com>

Incorrect calculation of the boundary condition when tracking lossy
rectangles in the worker thread will result in an OOB write which
can corrupt further worker state, and/or trigger any guard pages
that may lie beyond the VncWorker struct. This can be triggered
through careful choice of the display resolution in the guest
OS by an unprivileged user.

Fixes: CVE-2026-48002
Reported-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20260521103353.1645561-4-berrange@redhat.com>
[Marc-André - added assert() suggest by philmd@linaro.org]
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 ui/vnc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/ui/vnc.c b/ui/vnc.c
index 56dd43d53ff..375ab207950 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2982,13 +2982,15 @@ void vnc_sent_lossy_rect(VncWorker *worker, int x, int y, int w, int h)
 {
     int i, j;
 
-    w = (x + w) / VNC_STAT_RECT;
-    h = (y + h) / VNC_STAT_RECT;
+    w = DIV_ROUND_UP((x + w), VNC_STAT_RECT);
+    h = DIV_ROUND_UP((y + h), VNC_STAT_RECT);
+    assert(h <= VNC_STAT_ROWS);
+    assert(w <= VNC_STAT_COLS);
     x /= VNC_STAT_RECT;
     y /= VNC_STAT_RECT;
 
-    for (j = y; j <= h; j++) {
-        for (i = x; i <= w; i++) {
+    for (j = y; j < h; j++) {
+        for (i = x; i < w; i++) {
             worker->lossy_rect[j][i] = 1;
         }
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 07/38] ui/vnc: fix OOB read updating VNC update frequency stats
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (5 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 06/38] ui/vnc: fix OOB write in lossy rect worker code marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 08/38] ui: fix validation of VNC extended clipboard data length marcandre.lureau
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Daniel P. Berrangé, Marc-André Lureau

From: Daniel P. Berrangé <berrange@redhat.com>

Incorrect loop bounds in vnc_update_freq result in iterating past the
last row and past the last column in the VNC stats array. With suitably
chosen dimensions this could be a OOB read that accesses memory beyond
the VncDisplay struct that the stats array is embedded in.

Should this hit a guard page, it could trigger a guest crash. If it
does not, then the VNC frequency stats will be updated with garbage.

Fixes: CVE-2026-48003
Reported-by: boy juju <agx1657748706@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20260521103353.1645561-5-berrange@redhat.com>
---
 ui/vnc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/ui/vnc.c b/ui/vnc.c
index 375ab207950..2159bb35d54 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3093,12 +3093,14 @@ double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
     int i, j;
     double total = 0;
     int num = 0;
+    int x_end = x + w;
+    int y_end = y + h;
 
     x =  QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
     y =  QEMU_ALIGN_DOWN(y, VNC_STAT_RECT);
 
-    for (j = y; j <= y + h; j += VNC_STAT_RECT) {
-        for (i = x; i <= x + w; i += VNC_STAT_RECT) {
+    for (j = y; j < y_end; j += VNC_STAT_RECT) {
+        for (i = x; i < x_end; i += VNC_STAT_RECT) {
             total += vnc_stat_rect(vs->vd, i, j)->freq;
             num++;
         }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 08/38] ui: fix validation of VNC extended clipboard data length
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (6 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 07/38] ui/vnc: fix OOB read updating VNC update frequency stats marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 09/38] ui/input: Introduce QemuInputEvent typedef marcandre.lureau
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Heechan Kang, Daniel P. Berrangé,
	Marc-André Lureau

From: Heechan Kang <gganji11@naver.com>

QEMU's VNC extended clipboard handler inflates a client-controlled
compressed clipboard payload. The code checks the declared text size
against the total inflated buffer size:

    if (tsize < size)

but then copies from:

    tbuf = buf + 4;
    qemu_clipboard_set_data(..., tsize, tbuf, true);

The correct bound is the remaining data length after the 4-byte length
field, not the total inflated buffer length.

As a result, a VNC client can make QEMU copy up to 3 bytes past the end
of the inflated heap buffer. With a second VNC client, those copied
bytes are observable through the normal VNC extended clipboard PROVIDE
path.

Fixes: CVE-2026-8343
Reported-by: Heechan Kang <gganji11@naver.com>
Reported-by: Feifan Qian <bea1e@proton.me>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Heechan Kang <gganji11@naver.com>
[DB: added #include and 'return' statements]
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20260512095543.459949-1-berrange@redhat.com>
---
 ui/vnc-clipboard.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c
index 124b6fbd9c2..fa05d86f424 100644
--- a/ui/vnc-clipboard.c
+++ b/ui/vnc-clipboard.c
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/error-report.h"
 #include "vnc.h"
 #include "vnc-jobs.h"
 
@@ -282,10 +283,16 @@ void vnc_client_cut_text_ext(VncState *vs, int32_t len, uint32_t flags, uint8_t
             buf && size >= 4) {
             uint32_t tsize = read_u32(buf, 0);
             uint8_t *tbuf = buf + 4;
-            if (tsize < size) {
+            if (tsize <= size - 4) {
                 qemu_clipboard_set_data(&vs->cbpeer, vs->cbinfo,
                                         QEMU_CLIPBOARD_TYPE_TEXT,
                                         tsize, tbuf, true);
+            } else {
+                error_report("vnc: malformed extended clipboard payload "
+                             "with text length %u exceeding available %u",
+                             tsize, size - 4);
+                vnc_client_error(vs);
+                return;
             }
         }
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 09/38] ui/input: Introduce QemuInputEvent typedef
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (7 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 08/38] ui: fix validation of VNC extended clipboard data length marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 10/38] ui/input: Remove QAPI wrappers from QemuInputEvent marcandre.lureau
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Marc-André Lureau, Paolo Bonzini,
	Jan Kiszka, Peter Maydell, Stefano Stabellini, Anthony PERARD,
	Edgar E. Iglesias, Mark Cave-Ayland, Michael S. Tsirkin,
	Gerd Hoffmann, Thomas Huth, Alex Bennée, open list:Musicpal,
	open list:X86 Xen CPUs, open list:Old World (g3beige)

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

Add QemuInputEvent as the input subsystem's name for InputEvent and use
it in input handler, queue, and replay interfaces.

This prepares for decoupling QEMU's internal input event representation
from the QAPI InputEvent type.

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-1-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 include/qemu/typedefs.h      |  1 +
 include/system/replay.h      |  2 +-
 include/ui/input.h           |  6 +++---
 replay/replay-internal.h     |  6 +++---
 chardev/msmouse.c            |  2 +-
 chardev/wctablet.c           |  2 +-
 hw/arm/musicpal.c            |  2 +-
 hw/char/escc.c               |  4 ++--
 hw/display/xenfb.c           |  4 ++--
 hw/input/adb-kbd.c           |  2 +-
 hw/input/adb-mouse.c         |  2 +-
 hw/input/hid.c               |  4 ++--
 hw/input/ps2.c               |  4 ++--
 hw/input/stellaris_gamepad.c |  2 +-
 hw/input/virtio-input-hid.c  |  2 +-
 hw/m68k/next-kbd.c           |  3 ++-
 replay/replay-events.c       |  4 ++--
 replay/replay-input.c        |  8 ++++----
 replay/stubs-system.c        |  2 +-
 ui/input-legacy.c            |  2 +-
 ui/input.c                   | 26 +++++++++++++-------------
 ui/vdagent.c                 |  2 +-
 22 files changed, 47 insertions(+), 45 deletions(-)

diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 07f2ae7c9f1..da7097c5440 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -94,6 +94,7 @@ typedef struct QBool QBool;
 typedef struct QDict QDict;
 typedef struct QEMUBH QEMUBH;
 typedef struct QemuConsole QemuConsole;
+typedef struct InputEvent QemuInputEvent;
 typedef struct QEMUCursor QEMUCursor;
 typedef struct QEMUFile QEMUFile;
 typedef struct QemuMutex QemuMutex;
diff --git a/include/system/replay.h b/include/system/replay.h
index 19fb6dbb396..3b00386821b 100644
--- a/include/system/replay.h
+++ b/include/system/replay.h
@@ -126,7 +126,7 @@ void replay_bh_schedule_event(QEMUBH *bh);
 void replay_bh_schedule_oneshot_event(AioContext *ctx,
     QEMUBHFunc *cb, void *opaque);
 /*! Adds input event to the queue */
-void replay_input_event(QemuConsole *src, InputEvent *evt);
+void replay_input_event(QemuConsole *src, QemuInputEvent *evt);
 /*! Adds input sync event to the queue */
 void replay_input_sync_event(void);
 /*! Adds block layer event to the queue */
diff --git a/include/ui/input.h b/include/ui/input.h
index 52c164bde57..c455abdec6a 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -19,7 +19,7 @@ typedef struct QemuInputHandler QemuInputHandler;
 typedef struct QemuInputHandlerState QemuInputHandlerState;
 
 typedef void (*QemuInputHandlerEvent)(DeviceState *dev, QemuConsole *src,
-                                      InputEvent *evt);
+                                      QemuInputEvent *evt);
 typedef void (*QemuInputHandlerSync)(DeviceState *dev);
 
 struct QemuInputHandler {
@@ -37,8 +37,8 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s);
 void qemu_input_handler_bind(QemuInputHandlerState *s,
                              const char *device_id, int head,
                              Error **errp);
-void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
-void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt);
+void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt);
+void qemu_input_event_send_impl(QemuConsole *src, QemuInputEvent *evt);
 void qemu_input_event_sync(void);
 void qemu_input_event_sync_impl(void);
 
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 643b357da12..42c393542eb 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -171,11 +171,11 @@ void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque,
 /* Input events */
 
 /*! Saves input event to the log */
-void replay_save_input_event(InputEvent *evt);
+void replay_save_input_event(QemuInputEvent *evt);
 /*! Reads input event from the log */
-InputEvent *replay_read_input_event(void);
+QemuInputEvent *replay_read_input_event(void);
 /*! Adds input event to the queue */
-void replay_add_input_event(struct InputEvent *event);
+void replay_add_input_event(QemuInputEvent *event);
 /*! Adds input sync event to the queue */
 void replay_add_input_sync_event(void);
 
diff --git a/chardev/msmouse.c b/chardev/msmouse.c
index 365f04546e9..146457661f9 100644
--- a/chardev/msmouse.c
+++ b/chardev/msmouse.c
@@ -122,7 +122,7 @@ static void msmouse_queue_event(MouseChardev *mouse)
 }
 
 static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
-                                InputEvent *evt)
+                                QemuInputEvent *evt)
 {
     MouseChardev *mouse = MOUSE_CHARDEV(dev);
     InputMoveEvent *move;
diff --git a/chardev/wctablet.c b/chardev/wctablet.c
index 214d5ca2e28..05d2333fb0c 100644
--- a/chardev/wctablet.c
+++ b/chardev/wctablet.c
@@ -146,7 +146,7 @@ static void wctablet_queue_event(TabletChardev *tablet)
 }
 
 static void wctablet_input_event(DeviceState *dev, QemuConsole *src,
-                                InputEvent *evt)
+                                 QemuInputEvent *evt)
 {
     TabletChardev *tablet = (TabletChardev *)dev;
     InputMoveEvent *move;
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 83676eb7fea..ae171710e34 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1066,7 +1066,7 @@ struct musicpal_key_state {
 };
 
 static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
-                               InputEvent *evt)
+                               QemuInputEvent *evt)
 {
     musicpal_key_state *s = MUSICPAL_KEY(dev);
     InputKeyEvent *key = evt->u.key.data;
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 3b46818ecc9..677c3a120e1 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -794,7 +794,7 @@ static const VMStateDescription vmstate_escc = {
 };
 
 static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
-                                InputEvent *evt)
+                                QemuInputEvent *evt)
 {
     ESCCChannelState *s = (ESCCChannelState *)dev;
     int qcode, keycode;
@@ -954,7 +954,7 @@ static void handle_kbd_command(ESCCChannelState *s, int val)
 }
 
 static void sunmouse_handle_event(DeviceState *dev, QemuConsole *src,
-                                  InputEvent *evt)
+                                  QemuInputEvent *evt)
 {
     ESCCChannelState *s = (ESCCChannelState *)dev;
     InputMoveEvent *move;
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 8e9953bda43..c71174e1376 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -200,7 +200,7 @@ static int xenfb_send_position(struct XenInput *xenfb,
  * already has code for dealing with this...
  */
 static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
-                            InputEvent *evt)
+                            QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
     InputKeyEvent *key = evt->u.key.data;
@@ -227,7 +227,7 @@ static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
  * the button state.
  */
 static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
-                              InputEvent *evt)
+                              QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
     InputBtnEvent *btn;
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 507557deecc..5ba6c9a7b5d 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -306,7 +306,7 @@ static bool adb_kbd_has_data(ADBDevice *d)
 
 /* This is where keyboard events enter this file */
 static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
-                               InputEvent *evt)
+                               QemuInputEvent *evt)
 {
     KBDState *s = (KBDState *)dev;
     int qcode, keycode;
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 373ef3f953c..c37ccf26c16 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -56,7 +56,7 @@ struct ADBMouseClass {
 #define ADB_MOUSE_BUTTON_RIGHT  0x02
 
 static void adb_mouse_handle_event(DeviceState *dev, QemuConsole *src,
-                                   InputEvent *evt)
+                                   QemuInputEvent *evt)
 {
     MouseState *s = (MouseState *)dev;
     InputMoveEvent *move;
diff --git a/hw/input/hid.c b/hw/input/hid.c
index de24cd0ef04..53afb1d4340 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -108,7 +108,7 @@ void hid_set_next_idle(HIDState *hs)
 }
 
 static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
-                              InputEvent *evt)
+                              QemuInputEvent *evt)
 {
     static const int bmap[INPUT_BUTTON__MAX] = {
         [INPUT_BUTTON_LEFT]   = 0x01,
@@ -226,7 +226,7 @@ static void hid_pointer_sync(DeviceState *dev)
 }
 
 static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
-                               InputEvent *evt)
+                               QemuInputEvent *evt)
 {
     HIDState *hs = (HIDState *)dev;
     int scancodes[3], i, count;
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 10ac7324030..90bcbcdff88 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -310,7 +310,7 @@ static void ps2_put_keycode(void *opaque, int keycode)
 }
 
 static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
-                               InputEvent *evt)
+                               QemuInputEvent *evt)
 {
     PS2KbdState *s = (PS2KbdState *)dev;
     InputKeyEvent *key = evt->u.key.data;
@@ -787,7 +787,7 @@ static int ps2_mouse_send_packet(PS2MouseState *s)
 }
 
 static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
-                            InputEvent *evt)
+                            QemuInputEvent *evt)
 {
     static const int bmap[INPUT_BUTTON__MAX] = {
         [INPUT_BUTTON_LEFT]   = PS2_MOUSE_BUTTON_LEFT,
diff --git a/hw/input/stellaris_gamepad.c b/hw/input/stellaris_gamepad.c
index 42d43f9af51..db35905554d 100644
--- a/hw/input/stellaris_gamepad.c
+++ b/hw/input/stellaris_gamepad.c
@@ -16,7 +16,7 @@
 #include "ui/console.h"
 
 static void stellaris_gamepad_event(DeviceState *dev, QemuConsole *src,
-                                    InputEvent *evt)
+                                    QemuInputEvent *evt)
 {
     StellarisGamepad *s = STELLARIS_GAMEPAD(dev);
     InputKeyEvent *key = evt->u.key.data;
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 14dde90a48b..5b9f407c546 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -79,7 +79,7 @@ static void virtio_input_extend_config(VirtIOInput *vinput,
 }
 
 static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
-                                      InputEvent *evt)
+                                      QemuInputEvent *evt)
 {
     VirtIOInput *vinput = VIRTIO_INPUT(dev);
     virtio_input_event event;
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 571a9555040..9dbedac6479 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -242,7 +242,8 @@ static void nextkbd_put_keycode(NextKBDState *s, int keycode)
     /* s->update_irq(s->update_arg, 1); */
 }
 
-static void nextkbd_event(DeviceState *dev, QemuConsole *src, InputEvent *evt)
+static void nextkbd_event(DeviceState *dev, QemuConsole *src,
+                          QemuInputEvent *evt)
 {
     NextKBDState *s = NEXTKBD(dev);
     int qcode, keycode;
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 9e5af5e8495..20df810279e 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -41,7 +41,7 @@ static void replay_run_event(Event *event)
         ((QEMUBHFunc *)event->opaque)(event->opaque2);
         break;
     case REPLAY_ASYNC_EVENT_INPUT:
-        qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
+        qemu_input_event_send_impl(NULL, (QemuInputEvent *)event->opaque);
         qapi_free_InputEvent((InputEvent *)event->opaque);
         break;
     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
@@ -143,7 +143,7 @@ void replay_bh_schedule_oneshot_event(AioContext *ctx,
     }
 }
 
-void replay_add_input_event(struct InputEvent *event)
+void replay_add_input_event(QemuInputEvent *event)
 {
     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
 }
diff --git a/replay/replay-input.c b/replay/replay-input.c
index 562bbf37175..3f506f2338a 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -17,7 +17,7 @@
 #include "qapi/clone-visitor.h"
 #include "qapi/qapi-visit-ui.h"
 
-void replay_save_input_event(InputEvent *evt)
+void replay_save_input_event(QemuInputEvent *evt)
 {
     InputKeyEvent *key;
     InputBtnEvent *btn;
@@ -73,9 +73,9 @@ void replay_save_input_event(InputEvent *evt)
     }
 }
 
-InputEvent *replay_read_input_event(void)
+QemuInputEvent *replay_read_input_event(void)
 {
-    InputEvent evt;
+    QemuInputEvent evt;
     KeyValue keyValue;
     InputKeyEvent key;
     key.key = &keyValue;
@@ -135,7 +135,7 @@ InputEvent *replay_read_input_event(void)
     return QAPI_CLONE(InputEvent, &evt);
 }
 
-void replay_input_event(QemuConsole *src, InputEvent *evt)
+void replay_input_event(QemuConsole *src, QemuInputEvent *evt)
 {
     if (replay_mode == REPLAY_MODE_PLAY) {
         /* Nothing */
diff --git a/replay/stubs-system.c b/replay/stubs-system.c
index b2c52bc4043..f8e17dcf1ce 100644
--- a/replay/stubs-system.c
+++ b/replay/stubs-system.c
@@ -2,7 +2,7 @@
 #include "system/replay.h"
 #include "ui/input.h"
 
-void replay_input_event(QemuConsole *src, InputEvent *evt)
+void replay_input_event(QemuConsole *src, QemuInputEvent *evt)
 {
     qemu_input_event_send_impl(src, evt);
 }
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index ca4bccb4113..5467010c371 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -110,7 +110,7 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
 }
 
 static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
-                               InputEvent *evt)
+                               QemuInputEvent *evt)
 {
     static const int bmap[INPUT_BUTTON__MAX] = {
         [INPUT_BUTTON_LEFT]   = MOUSE_EVENT_LBUTTON,
diff --git a/ui/input.c b/ui/input.c
index 966023d4f4d..759855c67e8 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -30,7 +30,7 @@ struct QemuInputEventQueue {
     QEMUTimer *timer;
     uint32_t delay_ms;
     QemuConsole *src;
-    InputEvent *evt;
+    QemuInputEvent *evt;
     QTAILQ_ENTRY(QemuInputEventQueue) node;
 };
 
@@ -174,7 +174,7 @@ void qmp_input_send_event(const char *device,
     qemu_input_event_sync();
 }
 
-static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
+static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
 {
     const char *name;
     int qcode, idx = -1;
@@ -283,7 +283,7 @@ static void qemu_input_queue_delay(QemuInputEventQueueHead *queue,
 }
 
 static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
-                                   QemuConsole *src, InputEvent *evt)
+                                   QemuConsole *src, QemuInputEvent *evt)
 {
     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
 
@@ -303,7 +303,7 @@ static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
     queue_count++;
 }
 
-void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
+void qemu_input_event_send_impl(QemuConsole *src, QemuInputEvent *evt)
 {
     QemuInputHandlerState *s;
 
@@ -318,7 +318,7 @@ void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
     s->events++;
 }
 
-void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
+void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
 {
     /* Expect all parts of QEMU to send events with QCodes exclusively.
      * Key numbers are only supported as end-user input via QMP */
@@ -372,9 +372,9 @@ void qemu_input_event_sync(void)
     replay_input_sync_event();
 }
 
-static InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
+static QemuInputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
 {
-    InputEvent *evt = g_new0(InputEvent, 1);
+    QemuInputEvent *evt = g_new0(QemuInputEvent, 1);
     evt->u.key.data = g_new0(InputKeyEvent, 1);
     evt->type = INPUT_EVENT_KIND_KEY;
     evt->u.key.data->key = key;
@@ -384,7 +384,7 @@ static InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
 
 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
 {
-    InputEvent *evt;
+    QemuInputEvent *evt;
     evt = qemu_input_event_new_key(key, down);
     if (QTAILQ_EMPTY(&kbd_queue)) {
         qemu_input_event_send(src, evt);
@@ -435,7 +435,7 @@ void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
         .button = btn,
         .down = down,
     };
-    InputEvent evt = {
+    QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_BTN,
         .u.btn.data = &bevt,
     };
@@ -486,7 +486,7 @@ void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
         .axis = axis,
         .value = value,
     };
-    InputEvent evt = {
+    QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_REL,
         .u.rel.data = &move,
     };
@@ -503,7 +503,7 @@ void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
                                        INPUT_EVENT_ABS_MIN,
                                        INPUT_EVENT_ABS_MAX),
     };
-    InputEvent evt = {
+    QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_ABS,
         .u.abs.data = &move,
     };
@@ -519,7 +519,7 @@ void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
         .slot = slot,
         .tracking_id = tracking_id,
     };
-    InputEvent evt = {
+    QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_MTT,
         .u.mtt.data = &mtt,
     };
@@ -539,7 +539,7 @@ void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
                                        INPUT_EVENT_ABS_MIN,
                                        INPUT_EVENT_ABS_MAX),
     };
-    InputEvent evt = {
+    QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_MTT,
         .u.mtt.data = &mtt,
     };
diff --git a/ui/vdagent.c b/ui/vdagent.c
index bb55cbefc9c..28a83c7c389 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -226,7 +226,7 @@ static void vdagent_send_mouse(VDAgentChardev *vd)
 }
 
 static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
-                                  InputEvent *evt)
+                                  QemuInputEvent *evt)
 {
     static const int bmap[INPUT_BUTTON__MAX] = {
         [INPUT_BUTTON_LEFT]        = VD_AGENT_LBUTTON_MASK,
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 10/38] ui/input: Remove QAPI wrappers from QemuInputEvent
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (8 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 09/38] ui/input: Introduce QemuInputEvent typedef marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 11/38] ui/input: Store QKeyCode directly in QemuInputKeyEvent marcandre.lureau
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Marc-André Lureau, Paolo Bonzini,
	Jan Kiszka, Peter Maydell, Stefano Stabellini, Anthony PERARD,
	Edgar E. Iglesias, Mark Cave-Ayland, Michael S. Tsirkin,
	Gerd Hoffmann, Thomas Huth, Alex Bennée, open list:Musicpal,
	open list:X86 Xen CPUs, open list:New World (mac99)

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

QAPI represents union members with wrapper structs and pointer
indirections. They are useful at the QMP boundary, but unnecessary for
QEMU's internal input events and make handlers more verbose.

Define QemuInputEvent as a plain internal tagged union and convert input
handlers, queues, and replay code to access payloads directly.

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-2-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 include/qemu/typedefs.h      |   2 +-
 include/ui/input.h           |  16 ++++
 chardev/msmouse.c            |  10 +-
 chardev/wctablet.c           |   8 +-
 hw/arm/musicpal.c            |  11 +--
 hw/char/escc.c               |  32 +++----
 hw/display/xenfb.c           |  32 +++----
 hw/input/adb-kbd.c           |   4 +-
 hw/input/adb-mouse.c         |  20 ++--
 hw/input/hid.c               |  36 +++----
 hw/input/ps2.c               |  67 ++++++-------
 hw/input/stellaris_gamepad.c |   9 +-
 hw/input/virtio-input-hid.c  |  53 +++++------
 hw/m68k/next-kbd.c           |   9 +-
 replay/replay-events.c       |   2 +-
 replay/replay-input.c        | 101 ++++++++------------
 ui/input-legacy.c            |  23 ++---
 ui/input.c                   | 177 ++++++++++++++++++++---------------
 ui/vdagent.c                 |  18 ++--
 19 files changed, 299 insertions(+), 331 deletions(-)

diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index da7097c5440..2344c92182e 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -94,7 +94,7 @@ typedef struct QBool QBool;
 typedef struct QDict QDict;
 typedef struct QEMUBH QEMUBH;
 typedef struct QemuConsole QemuConsole;
-typedef struct InputEvent QemuInputEvent;
+typedef struct QemuInputEvent QemuInputEvent;
 typedef struct QEMUCursor QEMUCursor;
 typedef struct QEMUFile QEMUFile;
 typedef struct QemuMutex QemuMutex;
diff --git a/include/ui/input.h b/include/ui/input.h
index c455abdec6a..0b8c439fca7 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -18,6 +18,22 @@
 typedef struct QemuInputHandler QemuInputHandler;
 typedef struct QemuInputHandlerState QemuInputHandlerState;
 
+typedef struct QemuInputKeyEvent {
+    KeyValue key;
+    bool down;
+} QemuInputKeyEvent;
+
+typedef struct QemuInputEvent {
+    InputEventKind type;
+    union {
+        QemuInputKeyEvent key;
+        InputBtnEvent btn;
+        InputMoveEvent rel;
+        InputMoveEvent abs;
+        InputMultiTouchEvent mtt;
+    };
+} QemuInputEvent;
+
 typedef void (*QemuInputHandlerEvent)(DeviceState *dev, QemuConsole *src,
                                       QemuInputEvent *evt);
 typedef void (*QemuInputHandlerSync)(DeviceState *dev);
diff --git a/chardev/msmouse.c b/chardev/msmouse.c
index 146457661f9..d72a16a2833 100644
--- a/chardev/msmouse.c
+++ b/chardev/msmouse.c
@@ -125,8 +125,6 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
                                 QemuInputEvent *evt)
 {
     MouseChardev *mouse = MOUSE_CHARDEV(dev);
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
 
     /* Ignore events if serial mouse powered down. */
     if (!MSMOUSE_PWR(mouse->tiocm)) {
@@ -135,14 +133,12 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        mouse->axis[move->axis] += move->value;
+        mouse->axis[evt->rel.axis] += evt->rel.value;
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        mouse->btns[btn->button] = btn->down;
-        mouse->btnc[btn->button] = true;
+        mouse->btns[evt->btn.button] = evt->btn.down;
+        mouse->btnc[evt->btn.button] = true;
         break;
 
     default:
diff --git a/chardev/wctablet.c b/chardev/wctablet.c
index 05d2333fb0c..3ad24cce175 100644
--- a/chardev/wctablet.c
+++ b/chardev/wctablet.c
@@ -149,18 +149,14 @@ static void wctablet_input_event(DeviceState *dev, QemuConsole *src,
                                  QemuInputEvent *evt)
 {
     TabletChardev *tablet = (TabletChardev *)dev;
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
-        tablet->axis[move->axis] = move->value;
+        tablet->axis[evt->abs.axis] = evt->abs.value;
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        tablet->btns[btn->button] = btn->down;
+        tablet->btns[evt->btn.button] = evt->btn.down;
         break;
 
     default:
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index ae171710e34..43c93cb72d7 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1069,8 +1069,7 @@ static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     musicpal_key_state *s = MUSICPAL_KEY(dev);
-    InputKeyEvent *key = evt->u.key.data;
-    int qcode = qemu_input_key_value_to_qcode(key->key);
+    int qcode = qemu_input_key_value_to_qcode(&evt->key.key);
     uint32_t event = 0;
     int i;
 
@@ -1113,14 +1112,14 @@ static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
      * but do not repeat already-pressed buttons for the other key inputs.
      */
     if (!(event & (MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_VOL))) {
-        if (key->down && (s->pressed_keys & event)) {
+        if (evt->key.down && (s->pressed_keys & event)) {
             event = 0;
         }
     }
 
     if (event) {
         /* Raise GPIO pin first if repeating a key */
-        if (key->down && (s->pressed_keys & event)) {
+        if (evt->key.down && (s->pressed_keys & event)) {
             for (i = 0; i <= 7; i++) {
                 if (event & (1 << i)) {
                     qemu_set_irq(s->out[i], 1);
@@ -1129,10 +1128,10 @@ static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
         }
         for (i = 0; i <= 7; i++) {
             if (event & (1 << i)) {
-                qemu_set_irq(s->out[i], !key->down);
+                qemu_set_irq(s->out[i], !evt->key.down);
             }
         }
-        if (key->down) {
+        if (evt->key.down) {
             s->pressed_keys |= event;
         } else {
             s->pressed_keys &= ~event;
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 677c3a120e1..c88b2d54ebe 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -798,16 +798,14 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
 {
     ESCCChannelState *s = (ESCCChannelState *)dev;
     int qcode, keycode;
-    InputKeyEvent *key;
 
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    key = evt->u.key.data;
-    qcode = qemu_input_key_value_to_qcode(key->key);
+    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
     trace_escc_sunkbd_event_in(qcode, QKeyCode_str(qcode),
-                               key->down);
+                               evt->key.down);
 
     if (qcode == Q_KEY_CODE_CAPS_LOCK) {
-        if (key->down) {
+        if (evt->key.down) {
             s->caps_lock_mode ^= 1;
             if (s->caps_lock_mode == 2) {
                 return; /* Drop second press */
@@ -821,7 +819,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     }
 
     if (qcode == Q_KEY_CODE_NUM_LOCK) {
-        if (key->down) {
+        if (evt->key.down) {
             s->num_lock_mode ^= 1;
             if (s->num_lock_mode == 2) {
                 return; /* Drop second press */
@@ -839,7 +837,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     }
 
     keycode = qemu_input_map_qcode_to_sun[qcode];
-    if (!key->down) {
+    if (!evt->key.down) {
         keycode |= 0x80;
     }
     trace_escc_sunkbd_event_out(keycode);
@@ -957,8 +955,6 @@ static void sunmouse_handle_event(DeviceState *dev, QemuConsole *src,
                                   QemuInputEvent *evt)
 {
     ESCCChannelState *s = (ESCCChannelState *)dev;
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
     static const int bmap[INPUT_BUTTON__MAX] = {
         [INPUT_BUTTON_LEFT]   = 0x4,
         [INPUT_BUTTON_MIDDLE] = 0x2,
@@ -967,21 +963,19 @@ static void sunmouse_handle_event(DeviceState *dev, QemuConsole *src,
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        if (move->axis == INPUT_AXIS_X) {
-            s->sunmouse_dx += move->value;
-        } else if (move->axis == INPUT_AXIS_Y) {
-            s->sunmouse_dy -= move->value;
+        if (evt->rel.axis == INPUT_AXIS_X) {
+            s->sunmouse_dx += evt->rel.value;
+        } else if (evt->rel.axis == INPUT_AXIS_Y) {
+            s->sunmouse_dy -= evt->rel.value;
         }
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if (bmap[btn->button]) {
-            if (btn->down) {
-                s->sunmouse_buttons |= bmap[btn->button];
+        if (bmap[evt->btn.button]) {
+            if (evt->btn.down) {
+                s->sunmouse_buttons |= bmap[evt->btn.button];
             } else {
-                s->sunmouse_buttons &= ~bmap[btn->button];
+                s->sunmouse_buttons &= ~bmap[evt->btn.button];
             }
             /* Indicate we have a supported button event */
             s->sunmouse_buttons |= 0x80;
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index c71174e1376..82d2cbae7cc 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -203,16 +203,15 @@ static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
                             QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
-    InputKeyEvent *key = evt->u.key.data;
-    int qcode = qemu_input_key_value_to_qcode(key->key);
+    int qcode = qemu_input_key_value_to_qcode(&evt->key.key);
     int lnx;
 
     if (qcode < qemu_input_map_qcode_to_linux_len) {
         lnx = qemu_input_map_qcode_to_linux[qcode];
 
         if (lnx) {
-            trace_xenfb_key_event(xenfb, lnx, key->down);
-            xenfb_send_key(xenfb, key->down, lnx);
+            trace_xenfb_key_event(xenfb, lnx, evt->key.down);
+            xenfb_send_key(xenfb, evt->key.down, lnx);
         }
     }
 }
@@ -230,32 +229,29 @@ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
                               QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
-    InputBtnEvent *btn;
-    InputMoveEvent *move;
     QemuConsole *con;
     DisplaySurface *surface;
     int scale;
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        switch (btn->button) {
+        switch (evt->btn.button) {
         case INPUT_BUTTON_LEFT:
-            xenfb_send_key(xenfb, btn->down, BTN_LEFT);
+            xenfb_send_key(xenfb, evt->btn.down, BTN_LEFT);
             break;
         case INPUT_BUTTON_RIGHT:
-            xenfb_send_key(xenfb, btn->down, BTN_LEFT + 1);
+            xenfb_send_key(xenfb, evt->btn.down, BTN_LEFT + 1);
             break;
         case INPUT_BUTTON_MIDDLE:
-            xenfb_send_key(xenfb, btn->down, BTN_LEFT + 2);
+            xenfb_send_key(xenfb, evt->btn.down, BTN_LEFT + 2);
             break;
         case INPUT_BUTTON_WHEEL_UP:
-            if (btn->down) {
+            if (evt->btn.down) {
                 xenfb->wheel--;
             }
             break;
         case INPUT_BUTTON_WHEEL_DOWN:
-            if (btn->down) {
+            if (evt->btn.down) {
                 xenfb->wheel++;
             }
             break;
@@ -265,9 +261,8 @@ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
         break;
 
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
         if (xenfb->raw_pointer_wanted) {
-            xenfb->axis[move->axis] = move->value;
+            xenfb->axis[evt->abs.axis] = evt->abs.value;
         } else {
             con = qemu_console_lookup_by_index(0);
             if (!con) {
@@ -275,7 +270,7 @@ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
                 return;
             }
             surface = qemu_console_surface(con);
-            switch (move->axis) {
+            switch (evt->abs.axis) {
             case INPUT_AXIS_X:
                 scale = surface_width(surface) - 1;
                 break;
@@ -285,13 +280,12 @@ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
             default:
                 g_assert_not_reached();
             }
-            xenfb->axis[move->axis] = move->value * scale / 0x7fff;
+            xenfb->axis[evt->abs.axis] = evt->abs.value * scale / 0x7fff;
         }
         break;
 
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        xenfb->axis[move->axis] += move->value;
+        xenfb->axis[evt->rel.axis] += evt->rel.value;
         break;
 
     default:
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 5ba6c9a7b5d..5911e713925 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -311,7 +311,7 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
     KBDState *s = (KBDState *)dev;
     int qcode, keycode;
 
-    qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key);
+    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
     if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) {
         return;
     }
@@ -321,7 +321,7 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
         trace_adb_device_kbd_no_key();
         return;
     }
-    if (evt->u.key.data->down == false) { /* if key release event */
+    if (evt->key.down == false) { /* if key release event */
         keycode = keycode | 0x80;   /* create keyboard break code */
     }
 
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index c37ccf26c16..5dcdc851fcd 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -59,8 +59,6 @@ static void adb_mouse_handle_event(DeviceState *dev, QemuConsole *src,
                                    QemuInputEvent *evt)
 {
     MouseState *s = (MouseState *)dev;
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
     static const int bmap[INPUT_BUTTON__MAX] = {
         [INPUT_BUTTON_LEFT]   = ADB_MOUSE_BUTTON_LEFT,
         [INPUT_BUTTON_RIGHT]  = ADB_MOUSE_BUTTON_RIGHT,
@@ -68,21 +66,19 @@ static void adb_mouse_handle_event(DeviceState *dev, QemuConsole *src,
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        if (move->axis == INPUT_AXIS_X) {
-            s->dx += move->value;
-        } else if (move->axis == INPUT_AXIS_Y) {
-            s->dy += move->value;
+        if (evt->rel.axis == INPUT_AXIS_X) {
+            s->dx += evt->rel.value;
+        } else if (evt->rel.axis == INPUT_AXIS_Y) {
+            s->dy += evt->rel.value;
         }
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if (bmap[btn->button]) {
-            if (btn->down) {
-                s->buttons_state |= bmap[btn->button];
+        if (bmap[evt->btn.button]) {
+            if (evt->btn.down) {
+                s->buttons_state |= bmap[evt->btn.button];
             } else {
-                s->buttons_state &= ~bmap[btn->button];
+                s->buttons_state &= ~bmap[evt->btn.button];
             }
         }
         break;
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 53afb1d4340..90b29682a25 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -119,42 +119,37 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
     };
     HIDState *hs = (HIDState *)dev;
     HIDPointerEvent *e;
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
 
     assert(hs->n < QUEUE_LENGTH);
     e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        if (move->axis == INPUT_AXIS_X) {
-            e->xdx += move->value;
-        } else if (move->axis == INPUT_AXIS_Y) {
-            e->ydy += move->value;
+        if (evt->rel.axis == INPUT_AXIS_X) {
+            e->xdx += evt->rel.value;
+        } else if (evt->rel.axis == INPUT_AXIS_Y) {
+            e->ydy += evt->rel.value;
         }
         break;
 
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
-        if (move->axis == INPUT_AXIS_X) {
-            e->xdx = move->value;
-        } else if (move->axis == INPUT_AXIS_Y) {
-            e->ydy = move->value;
+        if (evt->abs.axis == INPUT_AXIS_X) {
+            e->xdx = evt->abs.value;
+        } else if (evt->abs.axis == INPUT_AXIS_Y) {
+            e->ydy = evt->abs.value;
         }
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if (btn->down) {
-            e->buttons_state |= bmap[btn->button];
-            if (btn->button == INPUT_BUTTON_WHEEL_UP) {
+        if (evt->btn.down) {
+            e->buttons_state |= bmap[evt->btn.button];
+            if (evt->btn.button == INPUT_BUTTON_WHEEL_UP) {
                 e->dz--;
-            } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+            } else if (evt->btn.button == INPUT_BUTTON_WHEEL_DOWN) {
                 e->dz++;
             }
         } else {
-            e->buttons_state &= ~bmap[btn->button];
+            e->buttons_state &= ~bmap[evt->btn.button];
         }
         break;
 
@@ -231,10 +226,9 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
     HIDState *hs = (HIDState *)dev;
     int scancodes[3], i, count;
     int slot;
-    InputKeyEvent *key = evt->u.key.data;
 
-    count = qemu_input_key_value_to_scancode(key->key,
-                                             key->down,
+    count = qemu_input_key_value_to_scancode(&evt->key.key,
+                                             evt->key.down,
                                              scancodes);
     if (hs->n + count > QUEUE_LENGTH) {
         trace_hid_kbd_queue_full();
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 90bcbcdff88..3e553176ef6 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -313,7 +313,6 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     PS2KbdState *s = (PS2KbdState *)dev;
-    InputKeyEvent *key = evt->u.key.data;
     int qcode;
     uint16_t keycode = 0;
     int mod;
@@ -325,12 +324,12 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
 
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    qcode = qemu_input_key_value_to_qcode(key->key);
+    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
 
     mod = ps2_modifier_bit(qcode);
-    trace_ps2_keyboard_event(s, qcode, key->down, mod,
+    trace_ps2_keyboard_event(s, qcode, evt->key.down, mod,
                              s->modifiers, s->scancode_set, s->translate);
-    if (key->down) {
+    if (evt->key.down) {
         s->modifiers |= mod;
     } else {
         s->modifiers &= ~mod;
@@ -339,14 +338,14 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
     if (s->scancode_set == 1) {
         if (qcode == Q_KEY_CODE_PAUSE) {
             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0x46);
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0xc6);
                 }
             } else {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe1);
                     ps2_put_keycode(s, 0x1d);
                     ps2_put_keycode(s, 0x45);
@@ -357,7 +356,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
             }
         } else if (qcode == Q_KEY_CODE_PRINT) {
             if (s->modifiers & MOD_ALT_L) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xb8);
                     ps2_put_keycode(s, 0x38);
                     ps2_put_keycode(s, 0x54);
@@ -367,7 +366,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0x38);
                 }
             } else if (s->modifiers & MOD_ALT_R) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0xb8);
                     ps2_put_keycode(s, 0xe0);
@@ -382,7 +381,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 }
             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
                                        MOD_SHIFT_R | MOD_CTRL_R)) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0x37);
                 } else {
@@ -390,7 +389,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0xb7);
                 }
             } else {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0x2a);
                     ps2_put_keycode(s, 0xe0);
@@ -403,7 +402,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 }
             }
         } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2)
-                   && !key->down) {
+                   && !evt->key.down) {
             /* Ignore release for these keys */
         } else {
             if (qcode < qemu_input_map_qcode_to_atset1_len) {
@@ -413,7 +412,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 if (keycode & 0xff00) {
                     ps2_put_keycode(s, keycode >> 8);
                 }
-                if (!key->down) {
+                if (!evt->key.down) {
                     keycode |= 0x80;
                 }
                 ps2_put_keycode(s, keycode & 0xff);
@@ -425,7 +424,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
     } else if (s->scancode_set == 2) {
         if (qcode == Q_KEY_CODE_PAUSE) {
             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0x7e);
                     ps2_put_keycode(s, 0xe0);
@@ -433,7 +432,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0x7e);
                 }
             } else {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe1);
                     ps2_put_keycode(s, 0x14);
                     ps2_put_keycode(s, 0x77);
@@ -446,7 +445,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
             }
         } else if (qcode == Q_KEY_CODE_PRINT) {
             if (s->modifiers & MOD_ALT_L) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xf0);
                     ps2_put_keycode(s, 0x11);
                     ps2_put_keycode(s, 0x11);
@@ -459,7 +458,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0x11);
                 }
             } else if (s->modifiers & MOD_ALT_R) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0xf0);
                     ps2_put_keycode(s, 0x11);
@@ -477,7 +476,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 }
             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
                                        MOD_SHIFT_R | MOD_CTRL_R)) {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0x7c);
                 } else {
@@ -486,7 +485,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0x7c);
                 }
             } else {
-                if (key->down) {
+                if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
                     ps2_put_keycode(s, 0x12);
                     ps2_put_keycode(s, 0xe0);
@@ -501,7 +500,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 }
             }
         } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2) &&
-                   !key->down) {
+                   !evt->key.down) {
             /* Ignore release for these keys */
         } else {
             if (qcode < qemu_input_map_qcode_to_atset2_len) {
@@ -511,7 +510,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 if (keycode & 0xff00) {
                     ps2_put_keycode(s, keycode >> 8);
                 }
-                if (!key->down) {
+                if (!evt->key.down) {
                     ps2_put_keycode(s, 0xf0);
                 }
                 ps2_put_keycode(s, keycode & 0xff);
@@ -526,7 +525,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
         }
         if (keycode) {
             /* FIXME: break code should be configured on a key by key basis */
-            if (!key->down) {
+            if (!evt->key.down) {
                 ps2_put_keycode(s, 0xf0);
             }
             ps2_put_keycode(s, keycode);
@@ -797,8 +796,6 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
         [INPUT_BUTTON_EXTRA]  = PS2_MOUSE_BUTTON_EXTRA,
     };
     PS2MouseState *s = (PS2MouseState *)dev;
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
 
     /* check if deltas are recorded when disabled */
     if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
@@ -807,31 +804,29 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        if (move->axis == INPUT_AXIS_X) {
-            s->mouse_dx += move->value;
-        } else if (move->axis == INPUT_AXIS_Y) {
-            s->mouse_dy -= move->value;
+        if (evt->rel.axis == INPUT_AXIS_X) {
+            s->mouse_dx += evt->rel.value;
+        } else if (evt->rel.axis == INPUT_AXIS_Y) {
+            s->mouse_dy -= evt->rel.value;
         }
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if (btn->down) {
-            s->mouse_buttons |= bmap[btn->button];
-            if (btn->button == INPUT_BUTTON_WHEEL_UP) {
+        if (evt->btn.down) {
+            s->mouse_buttons |= bmap[evt->btn.button];
+            if (evt->btn.button == INPUT_BUTTON_WHEEL_UP) {
                 s->mouse_dz--;
-            } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+            } else if (evt->btn.button == INPUT_BUTTON_WHEEL_DOWN) {
                 s->mouse_dz++;
             }
 
-            if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) {
+            if (evt->btn.button == INPUT_BUTTON_WHEEL_RIGHT) {
                 s->mouse_dw--;
-            } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) {
+            } else if (evt->btn.button == INPUT_BUTTON_WHEEL_LEFT) {
                 s->mouse_dw++;
             }
         } else {
-            s->mouse_buttons &= ~bmap[btn->button];
+            s->mouse_buttons &= ~bmap[evt->btn.button];
         }
         break;
 
diff --git a/hw/input/stellaris_gamepad.c b/hw/input/stellaris_gamepad.c
index db35905554d..7d8ec38e888 100644
--- a/hw/input/stellaris_gamepad.c
+++ b/hw/input/stellaris_gamepad.c
@@ -19,14 +19,13 @@ static void stellaris_gamepad_event(DeviceState *dev, QemuConsole *src,
                                     QemuInputEvent *evt)
 {
     StellarisGamepad *s = STELLARIS_GAMEPAD(dev);
-    InputKeyEvent *key = evt->u.key.data;
-    int qcode = qemu_input_key_value_to_qcode(key->key);
+    int qcode = qemu_input_key_value_to_qcode(&evt->key.key);
     int i;
 
     for (i = 0; i < s->num_buttons; i++) {
-        if (s->keycodes[i] == qcode && s->pressed[i] != key->down) {
-            s->pressed[i] = key->down;
-            qemu_set_irq(s->irqs[i], key->down);
+        if (s->keycodes[i] == qcode && s->pressed[i] != evt->key.down) {
+            s->pressed[i] = evt->key.down;
+            qemu_set_irq(s->irqs[i], evt->key.down);
         }
     }
 }
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 5b9f407c546..3f8a1bc249e 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -84,80 +84,71 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
     VirtIOInput *vinput = VIRTIO_INPUT(dev);
     virtio_input_event event;
     int qcode;
-    InputKeyEvent *key;
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
-    InputMultiTouchEvent *mtt;
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        key = evt->u.key.data;
-        qcode = qemu_input_key_value_to_qcode(key->key);
+        qcode = qemu_input_key_value_to_qcode(&evt->key.key);
         if (qcode < qemu_input_map_qcode_to_linux_len &&
             qemu_input_map_qcode_to_linux[qcode]) {
             event.type  = cpu_to_le16(EV_KEY);
             event.code  = cpu_to_le16(qemu_input_map_qcode_to_linux[qcode]);
-            event.value = cpu_to_le32(key->down ? 1 : 0);
+            event.value = cpu_to_le32(evt->key.down ? 1 : 0);
             virtio_input_send(vinput, &event);
         } else {
-            if (key->down) {
+            if (evt->key.down) {
                 fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
                         qcode, QKeyCode_str(qcode));
             }
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if ((btn->button == INPUT_BUTTON_WHEEL_UP ||
-             btn->button == INPUT_BUTTON_WHEEL_DOWN) &&
-            btn->down) {
+        if ((evt->btn.button == INPUT_BUTTON_WHEEL_UP ||
+             evt->btn.button == INPUT_BUTTON_WHEEL_DOWN) &&
+            evt->btn.down) {
             event.type  = cpu_to_le16(EV_REL);
             event.code  = cpu_to_le16(REL_WHEEL);
-            event.value = cpu_to_le32(btn->button == INPUT_BUTTON_WHEEL_UP
+            event.value = cpu_to_le32(evt->btn.button == INPUT_BUTTON_WHEEL_UP
                                       ? 1 : -1);
             virtio_input_send(vinput, &event);
-        } else if (keymap_button[btn->button]) {
+        } else if (keymap_button[evt->btn.button]) {
             event.type  = cpu_to_le16(EV_KEY);
-            event.code  = cpu_to_le16(keymap_button[btn->button]);
-            event.value = cpu_to_le32(btn->down ? 1 : 0);
+            event.code  = cpu_to_le16(keymap_button[evt->btn.button]);
+            event.value = cpu_to_le32(evt->btn.down ? 1 : 0);
             virtio_input_send(vinput, &event);
         } else {
-            if (btn->down) {
+            if (evt->btn.down) {
                 fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
-                        btn->button,
-                        InputButton_str(btn->button));
+                        evt->btn.button,
+                        InputButton_str(evt->btn.button));
             }
         }
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
         event.type  = cpu_to_le16(EV_REL);
-        event.code  = cpu_to_le16(axismap_rel[move->axis]);
-        event.value = cpu_to_le32(move->value);
+        event.code  = cpu_to_le16(axismap_rel[evt->rel.axis]);
+        event.value = cpu_to_le32(evt->rel.value);
         virtio_input_send(vinput, &event);
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
         event.type  = cpu_to_le16(EV_ABS);
-        event.code  = cpu_to_le16(axismap_abs[move->axis]);
-        event.value = cpu_to_le32(move->value);
+        event.code  = cpu_to_le16(axismap_abs[evt->abs.axis]);
+        event.value = cpu_to_le32(evt->abs.value);
         virtio_input_send(vinput, &event);
         break;
     case INPUT_EVENT_KIND_MTT:
-        mtt = evt->u.mtt.data;
-        if (mtt->type == INPUT_MULTI_TOUCH_TYPE_DATA) {
+        if (evt->mtt.type == INPUT_MULTI_TOUCH_TYPE_DATA) {
             event.type  = cpu_to_le16(EV_ABS);
-            event.code  = cpu_to_le16(axismap_tch[mtt->axis]);
-            event.value = cpu_to_le32(mtt->value);
+            event.code  = cpu_to_le16(axismap_tch[evt->mtt.axis]);
+            event.value = cpu_to_le32(evt->mtt.value);
             virtio_input_send(vinput, &event);
         } else {
             event.type  = cpu_to_le16(EV_ABS);
             event.code  = cpu_to_le16(ABS_MT_SLOT);
-            event.value = cpu_to_le32(mtt->slot);
+            event.value = cpu_to_le32(evt->mtt.slot);
             virtio_input_send(vinput, &event);
             event.type  = cpu_to_le16(EV_ABS);
             event.code  = cpu_to_le16(ABS_MT_TRACKING_ID);
-            event.value = cpu_to_le32(mtt->tracking_id);
+            event.value = cpu_to_le32(evt->mtt.tracking_id);
             virtio_input_send(vinput, &event);
         }
         break;
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 9dbedac6479..f3110ea0bca 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -247,16 +247,15 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
 {
     NextKBDState *s = NEXTKBD(dev);
     int qcode, keycode;
-    bool key_down = evt->u.key.data->down;
 
-    qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key);
+    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
     if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) {
         return;
     }
 
     /* Shift key currently has no keycode, so handle separately */
     if (qcode == Q_KEY_CODE_SHIFT) {
-        if (key_down) {
+        if (evt->key.down) {
             s->shift |= KD_LSHIFT;
         } else {
             s->shift &= ~KD_LSHIFT;
@@ -264,7 +263,7 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
     }
 
     if (qcode == Q_KEY_CODE_SHIFT_R) {
-        if (key_down) {
+        if (evt->key.down) {
             s->shift |= KD_RSHIFT;
         } else {
             s->shift &= ~KD_RSHIFT;
@@ -277,7 +276,7 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
     }
 
     /* If key release event, create keyboard break code */
-    if (!key_down) {
+    if (!evt->key.down) {
         keycode |= 0x80;
     }
 
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 20df810279e..3ff42acb06b 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -42,7 +42,7 @@ static void replay_run_event(Event *event)
         break;
     case REPLAY_ASYNC_EVENT_INPUT:
         qemu_input_event_send_impl(NULL, (QemuInputEvent *)event->opaque);
-        qapi_free_InputEvent((InputEvent *)event->opaque);
+        g_free(event->opaque);
         break;
     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
         qemu_input_event_sync_impl();
diff --git a/replay/replay-input.c b/replay/replay-input.c
index 3f506f2338a..0995b125f24 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -19,25 +19,20 @@
 
 void replay_save_input_event(QemuInputEvent *evt)
 {
-    InputKeyEvent *key;
-    InputBtnEvent *btn;
-    InputMoveEvent *move;
-    InputMultiTouchEvent *mtt;
     replay_put_dword(evt->type);
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        key = evt->u.key.data;
-        replay_put_dword(key->key->type);
+        replay_put_dword(evt->key.key.type);
 
-        switch (key->key->type) {
+        switch (evt->key.key.type) {
         case KEY_VALUE_KIND_NUMBER:
-            replay_put_qword(key->key->u.number.data);
-            replay_put_byte(key->down);
+            replay_put_qword(evt->key.key.u.number.data);
+            replay_put_byte(evt->key.down);
             break;
         case KEY_VALUE_KIND_QCODE:
-            replay_put_dword(key->key->u.qcode.data);
-            replay_put_byte(key->down);
+            replay_put_dword(evt->key.key.u.qcode.data);
+            replay_put_byte(evt->key.down);
             break;
         case KEY_VALUE_KIND__MAX:
             /* keep gcc happy */
@@ -45,27 +40,23 @@ void replay_save_input_event(QemuInputEvent *evt)
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        replay_put_dword(btn->button);
-        replay_put_byte(btn->down);
+        replay_put_dword(evt->btn.button);
+        replay_put_byte(evt->btn.down);
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        replay_put_dword(move->axis);
-        replay_put_qword(move->value);
+        replay_put_dword(evt->rel.axis);
+        replay_put_qword(evt->rel.value);
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
-        replay_put_dword(move->axis);
-        replay_put_qword(move->value);
+        replay_put_dword(evt->abs.axis);
+        replay_put_qword(evt->abs.value);
         break;
     case INPUT_EVENT_KIND_MTT:
-        mtt = evt->u.mtt.data;
-        replay_put_dword(mtt->type);
-        replay_put_qword(mtt->slot);
-        replay_put_qword(mtt->tracking_id);
-        replay_put_dword(mtt->axis);
-        replay_put_qword(mtt->value);
+        replay_put_dword(evt->mtt.type);
+        replay_put_qword(evt->mtt.slot);
+        replay_put_qword(evt->mtt.tracking_id);
+        replay_put_dword(evt->mtt.axis);
+        replay_put_qword(evt->mtt.value);
         break;
     case INPUT_EVENT_KIND__MAX:
         /* keep gcc happy */
@@ -75,29 +66,21 @@ void replay_save_input_event(QemuInputEvent *evt)
 
 QemuInputEvent *replay_read_input_event(void)
 {
-    QemuInputEvent evt;
-    KeyValue keyValue;
-    InputKeyEvent key;
-    key.key = &keyValue;
-    InputBtnEvent btn;
-    InputMoveEvent rel;
-    InputMoveEvent abs;
-    InputMultiTouchEvent mtt;
+    QemuInputEvent *evt = g_new(QemuInputEvent, 1);
 
-    evt.type = replay_get_dword();
-    switch (evt.type) {
+    evt->type = replay_get_dword();
+    switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        evt.u.key.data = &key;
-        evt.u.key.data->key->type = replay_get_dword();
+        evt->key.key.type = replay_get_dword();
 
-        switch (evt.u.key.data->key->type) {
+        switch (evt->key.key.type) {
         case KEY_VALUE_KIND_NUMBER:
-            evt.u.key.data->key->u.number.data = replay_get_qword();
-            evt.u.key.data->down = replay_get_byte();
+            evt->key.key.u.number.data = replay_get_qword();
+            evt->key.down = replay_get_byte();
             break;
         case KEY_VALUE_KIND_QCODE:
-            evt.u.key.data->key->u.qcode.data = (QKeyCode)replay_get_dword();
-            evt.u.key.data->down = replay_get_byte();
+            evt->key.key.u.qcode.data = (QKeyCode)replay_get_dword();
+            evt->key.down = replay_get_byte();
             break;
         case KEY_VALUE_KIND__MAX:
             /* keep gcc happy */
@@ -105,34 +88,30 @@ QemuInputEvent *replay_read_input_event(void)
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        evt.u.btn.data = &btn;
-        evt.u.btn.data->button = (InputButton)replay_get_dword();
-        evt.u.btn.data->down = replay_get_byte();
+        evt->btn.button = (InputButton)replay_get_dword();
+        evt->btn.down = replay_get_byte();
         break;
     case INPUT_EVENT_KIND_REL:
-        evt.u.rel.data = &rel;
-        evt.u.rel.data->axis = (InputAxis)replay_get_dword();
-        evt.u.rel.data->value = replay_get_qword();
+        evt->rel.axis = (InputAxis)replay_get_dword();
+        evt->rel.value = replay_get_qword();
         break;
     case INPUT_EVENT_KIND_ABS:
-        evt.u.abs.data = &abs;
-        evt.u.abs.data->axis = (InputAxis)replay_get_dword();
-        evt.u.abs.data->value = replay_get_qword();
+        evt->abs.axis = (InputAxis)replay_get_dword();
+        evt->abs.value = replay_get_qword();
         break;
     case INPUT_EVENT_KIND_MTT:
-        evt.u.mtt.data = &mtt;
-        evt.u.mtt.data->type = (InputMultiTouchType)replay_get_dword();
-        evt.u.mtt.data->slot = replay_get_qword();
-        evt.u.mtt.data->tracking_id = replay_get_qword();
-        evt.u.mtt.data->axis = (InputAxis)replay_get_dword();
-        evt.u.mtt.data->value = replay_get_qword();
+        evt->mtt.type = (InputMultiTouchType)replay_get_dword();
+        evt->mtt.slot = replay_get_qword();
+        evt->mtt.tracking_id = replay_get_qword();
+        evt->mtt.axis = (InputAxis)replay_get_dword();
+        evt->mtt.value = replay_get_qword();
         break;
     case INPUT_EVENT_KIND__MAX:
         /* keep gcc happy */
         break;
     }
 
-    return QAPI_CLONE(InputEvent, &evt);
+    return evt;
 }
 
 void replay_input_event(QemuConsole *src, QemuInputEvent *evt)
@@ -140,7 +119,9 @@ void replay_input_event(QemuConsole *src, QemuInputEvent *evt)
     if (replay_mode == REPLAY_MODE_PLAY) {
         /* Nothing */
     } else if (replay_mode == REPLAY_MODE_RECORD) {
-        replay_add_input_event(QAPI_CLONE(InputEvent, evt));
+        QemuInputEvent *clone = g_new(QemuInputEvent, 1);
+        *clone = *evt;
+        replay_add_input_event(clone);
     } else {
         qemu_input_event_send_impl(src, evt);
     }
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index 5467010c371..e2b48dd8f0a 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -118,39 +118,36 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
         [INPUT_BUTTON_RIGHT]  = MOUSE_EVENT_RBUTTON,
     };
     QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
-    InputBtnEvent *btn;
-    InputMoveEvent *move;
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if (btn->down) {
-            s->buttons |= bmap[btn->button];
+        if (evt->btn.down) {
+            s->buttons |= bmap[evt->btn.button];
         } else {
-            s->buttons &= ~bmap[btn->button];
+            s->buttons &= ~bmap[evt->btn.button];
         }
-        if (btn->down && btn->button == INPUT_BUTTON_WHEEL_UP) {
+        if (evt->btn.down && evt->btn.button == INPUT_BUTTON_WHEEL_UP) {
             s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
                                     s->axis[INPUT_AXIS_X],
                                     s->axis[INPUT_AXIS_Y],
                                     -1,
                                     s->buttons);
         }
-        if (btn->down && btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+        if (evt->btn.down && evt->btn.button == INPUT_BUTTON_WHEEL_DOWN) {
             s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
                                     s->axis[INPUT_AXIS_X],
                                     s->axis[INPUT_AXIS_Y],
                                     1,
                                     s->buttons);
         }
-        if (btn->down && btn->button == INPUT_BUTTON_WHEEL_RIGHT) {
+        if (evt->btn.down && evt->btn.button == INPUT_BUTTON_WHEEL_RIGHT) {
             s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
                                     s->axis[INPUT_AXIS_X],
                                     s->axis[INPUT_AXIS_Y],
                                     -2,
                                     s->buttons);
         }
-        if (btn->down && btn->button == INPUT_BUTTON_WHEEL_LEFT) {
+        if (evt->btn.down && evt->btn.button == INPUT_BUTTON_WHEEL_LEFT) {
             s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
                                     s->axis[INPUT_AXIS_X],
                                     s->axis[INPUT_AXIS_Y],
@@ -159,12 +156,10 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
         }
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
-        s->axis[move->axis] = move->value;
+        s->axis[evt->abs.axis] = evt->abs.value;
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
-        s->axis[move->axis] += move->value;
+        s->axis[evt->rel.axis] += evt->rel.value;
         break;
     default:
         break;
diff --git a/ui/input.c b/ui/input.c
index 759855c67e8..97c473f40a2 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -30,7 +30,7 @@ struct QemuInputEventQueue {
     QEMUTimer *timer;
     uint32_t delay_ms;
     QemuConsole *src;
-    QemuInputEvent *evt;
+    QemuInputEvent evt;
     QTAILQ_ENTRY(QemuInputEventQueue) node;
 };
 
@@ -159,16 +159,54 @@ void qmp_input_send_event(const char *device,
     }
 
     for (e = events; e != NULL; e = e->next) {
-        InputEvent *evt = e->value;
+        InputEvent *qapi = e->value;
+        QemuInputEvent evt;
+
+        evt.type = qapi->type;
+
+        switch (qapi->type) {
+        case INPUT_EVENT_KIND_KEY: {
+            KeyValue *key = qapi->u.key.data->key;
+            QKeyCode code;
+
+            switch (key->type) {
+            case KEY_VALUE_KIND_NUMBER:
+                code = qemu_input_key_number_to_qcode(key->u.number.data);
+                break;
+            case KEY_VALUE_KIND_QCODE:
+                code = key->u.qcode.data;
+                break;
+            default:
+                g_assert_not_reached();
+            }
+
+            evt.key.key.type = KEY_VALUE_KIND_QCODE;
+            evt.key.key.u.qcode.data = code;
+            evt.key.down = qapi->u.key.data->down;
+            break;
+        }
 
-        if (evt->type == INPUT_EVENT_KIND_KEY &&
-            evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER) {
-            KeyValue *key = evt->u.key.data->key;
-            QKeyCode code = qemu_input_key_number_to_qcode(key->u.number.data);
-            qemu_input_event_send_key_qcode(con, code, evt->u.key.data->down);
-        } else {
-            qemu_input_event_send(con, evt);
+        case INPUT_EVENT_KIND_BTN:
+            evt.btn = *qapi->u.btn.data;
+            break;
+
+        case INPUT_EVENT_KIND_REL:
+            evt.rel = *qapi->u.rel.data;
+            break;
+
+        case INPUT_EVENT_KIND_ABS:
+            evt.abs = *qapi->u.abs.data;
+            break;
+
+        case INPUT_EVENT_KIND_MTT:
+            evt.mtt = *qapi->u.mtt.data;
+            break;
+
+        default:
+            g_assert_not_reached();
         }
+
+        qemu_input_event_send(con, &evt);
     }
 
     qemu_input_event_sync();
@@ -178,7 +216,7 @@ static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
 {
     const char *name;
     int qcode, idx = -1;
-    InputKeyEvent *key;
+    QemuInputKeyEvent *key;
     InputBtnEvent *btn;
     InputMoveEvent *move;
     InputMultiTouchEvent *mtt;
@@ -188,16 +226,16 @@ static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
     }
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        key = evt->u.key.data;
-        switch (key->key->type) {
+        key = &evt->key;
+        switch (evt->key.key.type) {
         case KEY_VALUE_KIND_NUMBER:
-            qcode = qemu_input_key_number_to_qcode(key->key->u.number.data);
+            qcode = qemu_input_key_number_to_qcode(key->key.u.number.data);
             name = QKeyCode_str(qcode);
-            trace_input_event_key_number(idx, key->key->u.number.data,
+            trace_input_event_key_number(idx, key->key.u.number.data,
                                          name, key->down);
             break;
         case KEY_VALUE_KIND_QCODE:
-            name = QKeyCode_str(key->key->u.qcode.data);
+            name = QKeyCode_str(key->key.u.qcode.data);
             trace_input_event_key_qcode(idx, name, key->down);
             break;
         case KEY_VALUE_KIND__MAX:
@@ -206,22 +244,22 @@ static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
+        btn = &evt->btn;
         name = btn->button < INPUT_BUTTON__MAX ? InputButton_str(btn->button) : "invalid";
         trace_input_event_btn(idx, name, btn->down);
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel.data;
+        move = &evt->rel;
         name = move->axis < INPUT_AXIS__MAX ? InputAxis_str(move->axis) : "invalid";
         trace_input_event_rel(idx, name, move->value);
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
+        move = &evt->abs;
         name = move->axis < INPUT_AXIS__MAX ? InputAxis_str(move->axis) : "invalid";
         trace_input_event_abs(idx, name, move->value);
         break;
     case INPUT_EVENT_KIND_MTT:
-        mtt = evt->u.mtt.data;
+        mtt = &evt->mtt;
         name = mtt->axis < INPUT_AXIS__MAX ? InputAxis_str(mtt->axis) : "invalid";
         trace_input_event_mtt(idx, name, mtt->value);
         break;
@@ -251,8 +289,7 @@ static void qemu_input_queue_process(void *opaque)
                       + item->delay_ms);
             return;
         case QEMU_INPUT_QUEUE_EVENT:
-            qemu_input_event_send(item->src, item->evt);
-            qapi_free_InputEvent(item->evt);
+            qemu_input_event_send(item->src, &item->evt);
             break;
         case QEMU_INPUT_QUEUE_SYNC:
             qemu_input_event_sync();
@@ -289,7 +326,7 @@ static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
 
     item->type = QEMU_INPUT_QUEUE_EVENT;
     item->src = src;
-    item->evt = evt;
+    item->evt = *evt;
     QTAILQ_INSERT_TAIL(queue, item, node);
     queue_count++;
 }
@@ -323,7 +360,7 @@ void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
     /* Expect all parts of QEMU to send events with QCodes exclusively.
      * Key numbers are only supported as end-user input via QMP */
     assert(!(evt->type == INPUT_EVENT_KIND_KEY &&
-             evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER));
+             evt->key.key.type == KEY_VALUE_KIND_NUMBER));
 
 
     /*
@@ -335,8 +372,8 @@ void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
      * need to deal with this mistake
      */
     if (evt->type == INPUT_EVENT_KIND_KEY &&
-        evt->u.key.data->key->u.qcode.data == Q_KEY_CODE_SYSRQ) {
-        evt->u.key.data->key->u.qcode.data = Q_KEY_CODE_PRINT;
+        evt->key.key.u.qcode.data == Q_KEY_CODE_SYSRQ) {
+        evt->key.key.u.qcode.data = Q_KEY_CODE_PRINT;
     }
 
     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
@@ -372,29 +409,24 @@ void qemu_input_event_sync(void)
     replay_input_sync_event();
 }
 
-static QemuInputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
-{
-    QemuInputEvent *evt = g_new0(QemuInputEvent, 1);
-    evt->u.key.data = g_new0(InputKeyEvent, 1);
-    evt->type = INPUT_EVENT_KIND_KEY;
-    evt->u.key.data->key = key;
-    evt->u.key.data->down = down;
-    return evt;
-}
-
 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
 {
-    QemuInputEvent *evt;
-    evt = qemu_input_event_new_key(key, down);
+    QemuInputEvent evt = {
+        .type = INPUT_EVENT_KIND_KEY,
+        .key = {
+            .key = *key,
+            .down = down,
+        },
+    };
+
+    g_free(key);
+
     if (QTAILQ_EMPTY(&kbd_queue)) {
-        qemu_input_event_send(src, evt);
+        qemu_input_event_send(src, &evt);
         qemu_input_event_sync();
-        qapi_free_InputEvent(evt);
     } else if (queue_count < queue_limit) {
-        qemu_input_queue_event(&kbd_queue, src, evt);
+        qemu_input_queue_event(&kbd_queue, src, &evt);
         qemu_input_queue_sync(&kbd_queue);
-    } else {
-        qapi_free_InputEvent(evt);
     }
 }
 
@@ -431,13 +463,12 @@ void qemu_input_event_send_key_delay(uint32_t delay_ms)
 
 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
 {
-    InputBtnEvent bevt = {
-        .button = btn,
-        .down = down,
-    };
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_BTN,
-        .u.btn.data = &bevt,
+        .btn = {
+            .button = btn,
+            .down = down,
+        }
     };
 
     qemu_input_event_send(src, &evt);
@@ -482,13 +513,12 @@ int qemu_input_scale_axis(int value,
 
 void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
 {
-    InputMoveEvent move = {
-        .axis = axis,
-        .value = value,
-    };
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_REL,
-        .u.rel.data = &move,
+        .rel = {
+            .axis = axis,
+            .value = value,
+        },
     };
 
     qemu_input_event_send(src, &evt);
@@ -497,15 +527,14 @@ void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
 void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
                           int min_in, int max_in)
 {
-    InputMoveEvent move = {
-        .axis = axis,
-        .value = qemu_input_scale_axis(value, min_in, max_in,
-                                       INPUT_EVENT_ABS_MIN,
-                                       INPUT_EVENT_ABS_MAX),
-    };
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_ABS,
-        .u.abs.data = &move,
+        .abs = {
+            .axis = axis,
+            .value = qemu_input_scale_axis(value, min_in, max_in,
+                                           INPUT_EVENT_ABS_MIN,
+                                           INPUT_EVENT_ABS_MAX),
+        },
     };
 
     qemu_input_event_send(src, &evt);
@@ -514,14 +543,13 @@ void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
 void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
                           int slot, int tracking_id)
 {
-    InputMultiTouchEvent mtt = {
-        .type = type,
-        .slot = slot,
-        .tracking_id = tracking_id,
-    };
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_MTT,
-        .u.mtt.data = &mtt,
+        .mtt = {
+            .type = type,
+            .slot = slot,
+            .tracking_id = tracking_id,
+        },
     };
 
     qemu_input_event_send(src, &evt);
@@ -530,18 +558,17 @@ void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
 void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
                               int min_in, int max_in, int slot, int tracking_id)
 {
-    InputMultiTouchEvent mtt = {
-        .type = INPUT_MULTI_TOUCH_TYPE_DATA,
-        .slot = slot,
-        .tracking_id = tracking_id,
-        .axis = axis,
-        .value = qemu_input_scale_axis(value, min_in, max_in,
-                                       INPUT_EVENT_ABS_MIN,
-                                       INPUT_EVENT_ABS_MAX),
-    };
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_MTT,
-        .u.mtt.data = &mtt,
+        .mtt = {
+            .type = INPUT_MULTI_TOUCH_TYPE_DATA,
+            .slot = slot,
+            .tracking_id = tracking_id,
+            .axis = axis,
+            .value = qemu_input_scale_axis(value, min_in, max_in,
+                                           INPUT_EVENT_ABS_MIN,
+                                           INPUT_EVENT_ABS_MAX),
+        }
     };
 
     qemu_input_event_send(src, &evt);
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 28a83c7c389..8fa325bffa3 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -241,22 +241,19 @@ static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
     };
 
     VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
-    InputMoveEvent *move;
-    InputBtnEvent *btn;
     uint32_t xres, yres;
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs.data;
         xres = qemu_console_get_width(src, 1024);
         yres = qemu_console_get_height(src, 768);
-        if (move->axis == INPUT_AXIS_X) {
-            vd->mouse_x = qemu_input_scale_axis(move->value,
+        if (evt->abs.axis == INPUT_AXIS_X) {
+            vd->mouse_x = qemu_input_scale_axis(evt->abs.value,
                                                 INPUT_EVENT_ABS_MIN,
                                                 INPUT_EVENT_ABS_MAX,
                                                 0, xres);
-        } else if (move->axis == INPUT_AXIS_Y) {
-            vd->mouse_y = qemu_input_scale_axis(move->value,
+        } else if (evt->abs.axis == INPUT_AXIS_Y) {
+            vd->mouse_y = qemu_input_scale_axis(evt->abs.value,
                                                 INPUT_EVENT_ABS_MIN,
                                                 INPUT_EVENT_ABS_MAX,
                                                 0, yres);
@@ -265,11 +262,10 @@ static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn.data;
-        if (btn->down) {
-            vd->mouse_btn |= bmap[btn->button];
+        if (evt->btn.down) {
+            vd->mouse_btn |= bmap[evt->btn.button];
         } else {
-            vd->mouse_btn &= ~bmap[btn->button];
+            vd->mouse_btn &= ~bmap[evt->btn.button];
         }
         break;
 
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 11/38] ui/input: Store QKeyCode directly in QemuInputKeyEvent
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (9 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 10/38] ui/input: Remove QAPI wrappers from QemuInputEvent marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 12/38] ui/input: Use Linux key codes for internal key events marcandre.lureau
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Jan Kiszka, Peter Maydell,
	Marc-André Lureau, Paolo Bonzini, Stefano Stabellini,
	Anthony PERARD, Edgar E. Iglesias, Mark Cave-Ayland,
	Gerd Hoffmann, Michael S. Tsirkin, Thomas Huth, Alex Bennée,
	open list:Musicpal, open list:X86 Xen CPUs,
	open list:Old World (g3beige)

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

Since commit af07e5ff02ae ("ui: convert key events to QKeyCodes
immediately"), all internal key events are expected to be represented as
QKeyCode. Replace KeyValue in QemuInputKeyEvent with QKeyCode to enforce
that and simplify key code retrieval.

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-3-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 include/ui/input.h           |  5 ++---
 hw/arm/musicpal.c            |  2 +-
 hw/char/escc.c               |  2 +-
 hw/display/xenfb.c           |  2 +-
 hw/input/adb-kbd.c           |  2 +-
 hw/input/hid.c               |  5 ++---
 hw/input/ps2.c               |  2 +-
 hw/input/stellaris_gamepad.c |  2 +-
 hw/input/virtio-input-hid.c  |  2 +-
 hw/m68k/next-kbd.c           |  2 +-
 replay/replay-input.c        | 29 ++++++-----------------------
 ui/input-keymap.c            |  9 ++++-----
 ui/input.c                   | 34 +++++++---------------------------
 ui/trace-events              |  1 -
 14 files changed, 29 insertions(+), 70 deletions(-)

diff --git a/include/ui/input.h b/include/ui/input.h
index 0b8c439fca7..3c3dfa7b59d 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -19,7 +19,7 @@ typedef struct QemuInputHandler QemuInputHandler;
 typedef struct QemuInputHandlerState QemuInputHandlerState;
 
 typedef struct QemuInputKeyEvent {
-    KeyValue key;
+    QKeyCode key;
     bool down;
 } QemuInputKeyEvent;
 
@@ -65,8 +65,7 @@ void qemu_input_event_send_key_delay(uint32_t delay_ms);
 int qemu_input_key_number_to_qcode(unsigned int nr);
 int qemu_input_key_value_to_number(const KeyValue *value);
 int qemu_input_key_value_to_qcode(const KeyValue *value);
-int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
-                                     int *codes);
+int qemu_input_qcode_to_scancode(QKeyCode qcode, bool down, int *codes);
 int qemu_input_linux_to_qcode(unsigned int lnx);
 
 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 43c93cb72d7..f436bd13d91 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1069,7 +1069,7 @@ static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     musicpal_key_state *s = MUSICPAL_KEY(dev);
-    int qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    int qcode = evt->key.key;
     uint32_t event = 0;
     int i;
 
diff --git a/hw/char/escc.c b/hw/char/escc.c
index c88b2d54ebe..3ad803537e5 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -800,7 +800,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     int qcode, keycode;
 
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    qcode = evt->key.key;
     trace_escc_sunkbd_event_in(qcode, QKeyCode_str(qcode),
                                evt->key.down);
 
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 82d2cbae7cc..176796cbf62 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -203,7 +203,7 @@ static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
                             QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
-    int qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    int qcode = evt->key.key;
     int lnx;
 
     if (qcode < qemu_input_map_qcode_to_linux_len) {
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 5911e713925..db3c7777500 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -311,7 +311,7 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
     KBDState *s = (KBDState *)dev;
     int qcode, keycode;
 
-    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    qcode = evt->key.key;
     if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) {
         return;
     }
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 90b29682a25..31f6331c7d7 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -227,9 +227,8 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
     int scancodes[3], i, count;
     int slot;
 
-    count = qemu_input_key_value_to_scancode(&evt->key.key,
-                                             evt->key.down,
-                                             scancodes);
+    count = qemu_input_qcode_to_scancode(evt->key.key, evt->key.down,
+                                         scancodes);
     if (hs->n + count > QUEUE_LENGTH) {
         trace_hid_kbd_queue_full();
         return;
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 3e553176ef6..9090a0427bd 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -324,7 +324,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
 
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    qcode = evt->key.key;
 
     mod = ps2_modifier_bit(qcode);
     trace_ps2_keyboard_event(s, qcode, evt->key.down, mod,
diff --git a/hw/input/stellaris_gamepad.c b/hw/input/stellaris_gamepad.c
index 7d8ec38e888..6f42c46ddad 100644
--- a/hw/input/stellaris_gamepad.c
+++ b/hw/input/stellaris_gamepad.c
@@ -19,7 +19,7 @@ static void stellaris_gamepad_event(DeviceState *dev, QemuConsole *src,
                                     QemuInputEvent *evt)
 {
     StellarisGamepad *s = STELLARIS_GAMEPAD(dev);
-    int qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    int qcode = evt->key.key;
     int i;
 
     for (i = 0; i < s->num_buttons; i++) {
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 3f8a1bc249e..d48be1ea211 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -87,7 +87,7 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+        qcode = evt->key.key;
         if (qcode < qemu_input_map_qcode_to_linux_len &&
             qemu_input_map_qcode_to_linux[qcode]) {
             event.type  = cpu_to_le16(EV_KEY);
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index f3110ea0bca..39f223d0211 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -248,7 +248,7 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
     NextKBDState *s = NEXTKBD(dev);
     int qcode, keycode;
 
-    qcode = qemu_input_key_value_to_qcode(&evt->key.key);
+    qcode = evt->key.key;
     if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) {
         return;
     }
diff --git a/replay/replay-input.c b/replay/replay-input.c
index 0995b125f24..f1ee678ef72 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -23,21 +23,9 @@ void replay_save_input_event(QemuInputEvent *evt)
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        replay_put_dword(evt->key.key.type);
-
-        switch (evt->key.key.type) {
-        case KEY_VALUE_KIND_NUMBER:
-            replay_put_qword(evt->key.key.u.number.data);
-            replay_put_byte(evt->key.down);
-            break;
-        case KEY_VALUE_KIND_QCODE:
-            replay_put_dword(evt->key.key.u.qcode.data);
-            replay_put_byte(evt->key.down);
-            break;
-        case KEY_VALUE_KIND__MAX:
-            /* keep gcc happy */
-            break;
-        }
+        replay_put_dword(KEY_VALUE_KIND_QCODE);
+        replay_put_dword(evt->key.key);
+        replay_put_byte(evt->key.down);
         break;
     case INPUT_EVENT_KIND_BTN:
         replay_put_dword(evt->btn.button);
@@ -71,20 +59,15 @@ QemuInputEvent *replay_read_input_event(void)
     evt->type = replay_get_dword();
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        evt->key.key.type = replay_get_dword();
-
-        switch (evt->key.key.type) {
+        switch (replay_get_dword()) {
         case KEY_VALUE_KIND_NUMBER:
-            evt->key.key.u.number.data = replay_get_qword();
+            evt->key.key = qemu_input_key_number_to_qcode(replay_get_qword());
             evt->key.down = replay_get_byte();
             break;
         case KEY_VALUE_KIND_QCODE:
-            evt->key.key.u.qcode.data = (QKeyCode)replay_get_dword();
+            evt->key.key = (QKeyCode)replay_get_dword();
             evt->key.down = replay_get_byte();
             break;
-        case KEY_VALUE_KIND__MAX:
-            /* keep gcc happy */
-            break;
         }
         break;
     case INPUT_EVENT_KIND_BTN:
diff --git a/ui/input-keymap.c b/ui/input-keymap.c
index 1b756a6970c..2f6d431c824 100644
--- a/ui/input-keymap.c
+++ b/ui/input-keymap.c
@@ -61,14 +61,13 @@ int qemu_input_key_value_to_qcode(const KeyValue *value)
     }
 }
 
-int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
-                                     int *codes)
+int qemu_input_qcode_to_scancode(QKeyCode qcode, bool down, int *codes)
 {
-    int keycode = qemu_input_key_value_to_number(value);
+    int keycode = qcode < qemu_input_map_qcode_to_qnum_len ?
+                  qemu_input_map_qcode_to_qnum[qcode] : 0;
     int count = 0;
 
-    if (value->type == KEY_VALUE_KIND_QCODE &&
-        value->u.qcode.data == Q_KEY_CODE_PAUSE) {
+    if (qcode == Q_KEY_CODE_PAUSE) {
         /* specific case */
         int v = down ? 0 : 0x80;
         codes[count++] = 0xe1;
diff --git a/ui/input.c b/ui/input.c
index 97c473f40a2..9232dd7fdae 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -180,8 +180,7 @@ void qmp_input_send_event(const char *device,
                 g_assert_not_reached();
             }
 
-            evt.key.key.type = KEY_VALUE_KIND_QCODE;
-            evt.key.key.u.qcode.data = code;
+            evt.key.key = code;
             evt.key.down = qapi->u.key.data->down;
             break;
         }
@@ -215,7 +214,7 @@ void qmp_input_send_event(const char *device,
 static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
 {
     const char *name;
-    int qcode, idx = -1;
+    int idx = -1;
     QemuInputKeyEvent *key;
     InputBtnEvent *btn;
     InputMoveEvent *move;
@@ -227,21 +226,8 @@ static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
         key = &evt->key;
-        switch (evt->key.key.type) {
-        case KEY_VALUE_KIND_NUMBER:
-            qcode = qemu_input_key_number_to_qcode(key->key.u.number.data);
-            name = QKeyCode_str(qcode);
-            trace_input_event_key_number(idx, key->key.u.number.data,
-                                         name, key->down);
-            break;
-        case KEY_VALUE_KIND_QCODE:
-            name = QKeyCode_str(key->key.u.qcode.data);
-            trace_input_event_key_qcode(idx, name, key->down);
-            break;
-        case KEY_VALUE_KIND__MAX:
-            /* keep gcc happy */
-            break;
-        }
+        name = QKeyCode_str(key->key);
+        trace_input_event_key_qcode(idx, name, key->down);
         break;
     case INPUT_EVENT_KIND_BTN:
         btn = &evt->btn;
@@ -357,12 +343,6 @@ void qemu_input_event_send_impl(QemuConsole *src, QemuInputEvent *evt)
 
 void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
 {
-    /* Expect all parts of QEMU to send events with QCodes exclusively.
-     * Key numbers are only supported as end-user input via QMP */
-    assert(!(evt->type == INPUT_EVENT_KIND_KEY &&
-             evt->key.key.type == KEY_VALUE_KIND_NUMBER));
-
-
     /*
      * 'sysrq' was mistakenly added to hack around the fact that
      * the ps2 driver was not generating correct scancodes sequences
@@ -372,8 +352,8 @@ void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
      * need to deal with this mistake
      */
     if (evt->type == INPUT_EVENT_KIND_KEY &&
-        evt->key.key.u.qcode.data == Q_KEY_CODE_SYSRQ) {
-        evt->key.key.u.qcode.data = Q_KEY_CODE_PRINT;
+        evt->key.key == Q_KEY_CODE_SYSRQ) {
+        evt->key.key = Q_KEY_CODE_PRINT;
     }
 
     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
@@ -414,7 +394,7 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_KEY,
         .key = {
-            .key = *key,
+            .key = qemu_input_key_value_to_qcode(key),
             .down = down,
         },
     };
diff --git a/ui/trace-events b/ui/trace-events
index c1ea56874ee..1c0d96a92c3 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -127,7 +127,6 @@ vnc_tight_zlib_init(void *state, int stream_id, const void *opaque) "VNC tight z
 
 
 # input.c
-input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d"
 input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
 input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d"
 input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d"
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 12/38] ui/input: Use Linux key codes for internal key events
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (10 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 11/38] ui/input: Store QKeyCode directly in QemuInputKeyEvent marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 13/38] ui/input: Prohibit sending KEY_RESERVED marcandre.lureau
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Jan Kiszka, Peter Maydell,
	Marc-André Lureau, Paolo Bonzini, Stefano Stabellini,
	Anthony PERARD, Edgar E. Iglesias, Mark Cave-Ayland,
	Gerd Hoffmann, Michael S. Tsirkin, Thomas Huth, Alex Bennée,
	open list:Musicpal, open list:X86 Xen CPUs,
	open list:Old World (g3beige)

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

Linux input key codes are a better internal representation than
QKeyCode:

- With Linux input key codes as the internal representation, keys
  previously lost solely because the middle layer between event sources
  and sinks used QKeyCode will be preserved, since Linux key codes
  cover all keys that those sources and sinks use. For example,
  KEY_KPJPCOMMA cannot be represented with QKeyCode, but it is widely
  supported by event sources and sinks since it is included in linux,
  atset1, atset2, usb, x11, osx, qnum (derived from atset1),
  xorgxquartz, and xorgevdev (derived from linux).

- They make it possible to pass through Linux host key codes to Linux
  guests to preserve all key inputs.

- They simplify consumers by avoiding QKeyCode aliases, namely
  asterisk/kp_multiply and sysrq/print.

This matches the approach used by virtio and Xen.

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-4-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 include/ui/input.h           | 49 ++++++++++++++++++++++++++++++-
 hw/arm/musicpal.c            |  2 +-
 hw/char/escc.c               |  2 +-
 hw/display/xenfb.c           |  2 +-
 hw/input/adb-kbd.c           |  2 +-
 hw/input/hid.c               |  3 +-
 hw/input/ps2.c               |  2 +-
 hw/input/stellaris_gamepad.c |  2 +-
 hw/input/virtio-input-hid.c  |  2 +-
 hw/m68k/next-kbd.c           |  2 +-
 replay/replay-input.c        | 11 +++++--
 tools/qemu-vnc/input.c       | 13 +++++++--
 ui/input-keymap.c            | 56 +++++++++++++++++++++++++++++-------
 ui/input.c                   | 51 ++++++++++----------------------
 tools/qemu-vnc/trace-events  |  2 +-
 ui/meson.build               | 14 +++++++++
 16 files changed, 151 insertions(+), 64 deletions(-)

diff --git a/include/ui/input.h b/include/ui/input.h
index 3c3dfa7b59d..e76dd4b172a 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -19,7 +19,7 @@ typedef struct QemuInputHandler QemuInputHandler;
 typedef struct QemuInputHandlerState QemuInputHandlerState;
 
 typedef struct QemuInputKeyEvent {
-    QKeyCode key;
+    unsigned int key;
     bool down;
 } QemuInputKeyEvent;
 
@@ -59,13 +59,18 @@ void qemu_input_event_sync(void);
 void qemu_input_event_sync_impl(void);
 
 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
+void qemu_input_event_send_key_linux(QemuConsole *src, unsigned int lnx,
+                                     bool down);
 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
 void qemu_input_event_send_key_delay(uint32_t delay_ms);
 int qemu_input_key_number_to_qcode(unsigned int nr);
+unsigned int qemu_input_key_number_to_linux(unsigned int nr);
 int qemu_input_key_value_to_number(const KeyValue *value);
 int qemu_input_key_value_to_qcode(const KeyValue *value);
+unsigned int qemu_input_key_value_to_linux(const KeyValue *value);
 int qemu_input_qcode_to_scancode(QKeyCode qcode, bool down, int *codes);
+int qemu_input_linux_to_scancode(unsigned int lnx, bool down, int *codes);
 int qemu_input_linux_to_qcode(unsigned int lnx);
 
 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
@@ -107,52 +112,94 @@ void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
 extern const guint qemu_input_map_atset1_to_qcode_len;
 extern const guint16 qemu_input_map_atset1_to_qcode[];
 
+extern const guint qemu_input_map_atset1_to_linux_len;
+extern const guint16 qemu_input_map_atset1_to_linux[];
+
 extern const guint qemu_input_map_linux_to_qcode_len;
 extern const guint16 qemu_input_map_linux_to_qcode[];
 
 extern const guint qemu_input_map_qcode_to_atset1_len;
 extern const guint16 qemu_input_map_qcode_to_atset1[];
 
+extern const guint qemu_input_map_linux_to_atset1_len;
+extern const guint16 qemu_input_map_linux_to_atset1[];
+
 extern const guint qemu_input_map_qcode_to_atset2_len;
 extern const guint16 qemu_input_map_qcode_to_atset2[];
 
+extern const guint qemu_input_map_linux_to_atset2_len;
+extern const guint16 qemu_input_map_linux_to_atset2[];
+
 extern const guint qemu_input_map_qcode_to_atset3_len;
 extern const guint16 qemu_input_map_qcode_to_atset3[];
 
+extern const guint qemu_input_map_linux_to_atset3_len;
+extern const guint16 qemu_input_map_linux_to_atset3[];
+
 extern const guint qemu_input_map_qcode_to_linux_len;
 extern const guint16 qemu_input_map_qcode_to_linux[];
 
 extern const guint qemu_input_map_qcode_to_qnum_len;
 extern const guint16 qemu_input_map_qcode_to_qnum[];
 
+extern const guint qemu_input_map_linux_to_qnum_len;
+extern const guint16 qemu_input_map_linux_to_qnum[];
+
 extern const guint qemu_input_map_qcode_to_sun_len;
 extern const guint16 qemu_input_map_qcode_to_sun[];
 
+extern const guint qemu_input_map_linux_to_sun_len;
+extern const guint16 qemu_input_map_linux_to_sun[];
+
 extern const guint qemu_input_map_qnum_to_qcode_len;
 extern const guint16 qemu_input_map_qnum_to_qcode[];
 
+extern const guint qemu_input_map_qnum_to_linux_len;
+extern const guint16 qemu_input_map_qnum_to_linux[];
+
 extern const guint qemu_input_map_usb_to_qcode_len;
 extern const guint16 qemu_input_map_usb_to_qcode[];
 
+extern const guint qemu_input_map_usb_to_linux_len;
+extern const guint16 qemu_input_map_usb_to_linux[];
+
 extern const guint qemu_input_map_win32_to_qcode_len;
 extern const guint16 qemu_input_map_win32_to_qcode[];
 
+extern const guint qemu_input_map_win32_to_linux_len;
+extern const guint16 qemu_input_map_win32_to_linux[];
+
 extern const guint qemu_input_map_x11_to_qcode_len;
 extern const guint16 qemu_input_map_x11_to_qcode[];
 
+extern const guint qemu_input_map_x11_to_linux_len;
+extern const guint16 qemu_input_map_x11_to_linux[];
+
 extern const guint qemu_input_map_xorgevdev_to_qcode_len;
 extern const guint16 qemu_input_map_xorgevdev_to_qcode[];
 
 extern const guint qemu_input_map_xorgkbd_to_qcode_len;
 extern const guint16 qemu_input_map_xorgkbd_to_qcode[];
 
+extern const guint qemu_input_map_xorgkbd_to_linux_len;
+extern const guint16 qemu_input_map_xorgkbd_to_linux[];
+
 extern const guint qemu_input_map_xorgxquartz_to_qcode_len;
 extern const guint16 qemu_input_map_xorgxquartz_to_qcode[];
 
+extern const guint qemu_input_map_xorgxquartz_to_linux_len;
+extern const guint16 qemu_input_map_xorgxquartz_to_linux[];
+
 extern const guint qemu_input_map_xorgxwin_to_qcode_len;
 extern const guint16 qemu_input_map_xorgxwin_to_qcode[];
 
+extern const guint qemu_input_map_xorgxwin_to_linux_len;
+extern const guint16 qemu_input_map_xorgxwin_to_linux[];
+
 extern const guint qemu_input_map_osx_to_qcode_len;
 extern const guint16 qemu_input_map_osx_to_qcode[];
 
+extern const guint qemu_input_map_osx_to_linux_len;
+extern const guint16 qemu_input_map_osx_to_linux[];
+
 #endif /* INPUT_H */
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index f436bd13d91..c8985a58f99 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1069,7 +1069,7 @@ static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     musicpal_key_state *s = MUSICPAL_KEY(dev);
-    int qcode = evt->key.key;
+    int qcode = qemu_input_linux_to_qcode(evt->key.key);
     uint32_t event = 0;
     int i;
 
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 3ad803537e5..39483ca03bf 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -800,7 +800,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     int qcode, keycode;
 
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    qcode = evt->key.key;
+    qcode = qemu_input_linux_to_qcode(evt->key.key);
     trace_escc_sunkbd_event_in(qcode, QKeyCode_str(qcode),
                                evt->key.down);
 
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 176796cbf62..218f37f0740 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -203,7 +203,7 @@ static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
                             QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
-    int qcode = evt->key.key;
+    int qcode = qemu_input_linux_to_qcode(evt->key.key);
     int lnx;
 
     if (qcode < qemu_input_map_qcode_to_linux_len) {
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index db3c7777500..060481d0db6 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -311,7 +311,7 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
     KBDState *s = (KBDState *)dev;
     int qcode, keycode;
 
-    qcode = evt->key.key;
+    qcode = qemu_input_linux_to_qcode(evt->key.key);
     if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) {
         return;
     }
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 31f6331c7d7..013840562f6 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -224,10 +224,11 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     HIDState *hs = (HIDState *)dev;
+    int qcode = qemu_input_linux_to_qcode(evt->key.key);
     int scancodes[3], i, count;
     int slot;
 
-    count = qemu_input_qcode_to_scancode(evt->key.key, evt->key.down,
+    count = qemu_input_qcode_to_scancode(qcode, evt->key.down,
                                          scancodes);
     if (hs->n + count > QUEUE_LENGTH) {
         trace_hid_kbd_queue_full();
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 9090a0427bd..93c3c737205 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -324,7 +324,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
 
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    qcode = evt->key.key;
+    qcode = qemu_input_linux_to_qcode(evt->key.key);
 
     mod = ps2_modifier_bit(qcode);
     trace_ps2_keyboard_event(s, qcode, evt->key.down, mod,
diff --git a/hw/input/stellaris_gamepad.c b/hw/input/stellaris_gamepad.c
index 6f42c46ddad..25769fc2616 100644
--- a/hw/input/stellaris_gamepad.c
+++ b/hw/input/stellaris_gamepad.c
@@ -19,7 +19,7 @@ static void stellaris_gamepad_event(DeviceState *dev, QemuConsole *src,
                                     QemuInputEvent *evt)
 {
     StellarisGamepad *s = STELLARIS_GAMEPAD(dev);
-    int qcode = evt->key.key;
+    int qcode = qemu_input_linux_to_qcode(evt->key.key);
     int i;
 
     for (i = 0; i < s->num_buttons; i++) {
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index d48be1ea211..1d2e922567a 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -87,7 +87,7 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        qcode = evt->key.key;
+        qcode = qemu_input_linux_to_qcode(evt->key.key);
         if (qcode < qemu_input_map_qcode_to_linux_len &&
             qemu_input_map_qcode_to_linux[qcode]) {
             event.type  = cpu_to_le16(EV_KEY);
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 39f223d0211..7efbd806b7c 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -248,7 +248,7 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
     NextKBDState *s = NEXTKBD(dev);
     int qcode, keycode;
 
-    qcode = evt->key.key;
+    qcode = qemu_input_linux_to_qcode(evt->key.key);
     if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) {
         return;
     }
diff --git a/replay/replay-input.c b/replay/replay-input.c
index f1ee678ef72..acf0993c728 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -24,7 +24,7 @@ void replay_save_input_event(QemuInputEvent *evt)
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
         replay_put_dword(KEY_VALUE_KIND_QCODE);
-        replay_put_dword(evt->key.key);
+        replay_put_dword(qemu_input_linux_to_qcode(evt->key.key));
         replay_put_byte(evt->key.down);
         break;
     case INPUT_EVENT_KIND_BTN:
@@ -55,20 +55,25 @@ void replay_save_input_event(QemuInputEvent *evt)
 QemuInputEvent *replay_read_input_event(void)
 {
     QemuInputEvent *evt = g_new(QemuInputEvent, 1);
+    int qcode;
 
     evt->type = replay_get_dword();
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
         switch (replay_get_dword()) {
         case KEY_VALUE_KIND_NUMBER:
-            evt->key.key = qemu_input_key_number_to_qcode(replay_get_qword());
+            qcode = qemu_input_key_number_to_qcode(replay_get_qword());
             evt->key.down = replay_get_byte();
             break;
         case KEY_VALUE_KIND_QCODE:
-            evt->key.key = (QKeyCode)replay_get_dword();
+            qcode = (QKeyCode)replay_get_dword();
             evt->key.down = replay_get_byte();
             break;
+        default:
+            g_assert_not_reached();
         }
+        evt->key.key = qcode < qemu_input_map_qcode_to_linux_len ?
+                       qemu_input_map_qcode_to_linux[qcode] : 0;
         break;
     case INPUT_EVENT_KIND_BTN:
         evt->btn.button = (InputButton)replay_get_dword();
diff --git a/tools/qemu-vnc/input.c b/tools/qemu-vnc/input.c
index 2313b0a7c77..90e2e79d1ea 100644
--- a/tools/qemu-vnc/input.c
+++ b/tools/qemu-vnc/input.c
@@ -82,11 +82,18 @@ void qemu_input_event_send_key_delay(uint32_t delay_ms)
 }
 
 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
+{
+    unsigned int lnx = qemu_input_map_qcode_to_linux[q];
+    qemu_input_event_send_key_linux(src, lnx, down);
+}
+
+void qemu_input_event_send_key_linux(QemuConsole *src, unsigned int lnx,
+                                     bool down)
 {
     QemuDBusDisplay1Keyboard *kbd;
     guint qnum;
 
-    trace_qemu_vnc_key_event(q, down);
+    trace_qemu_vnc_key_event(lnx, down);
 
     if (!src) {
         return;
@@ -96,10 +103,10 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
         return;
     }
 
-    if (q >= qemu_input_map_qcode_to_qnum_len) {
+    if (lnx >= qemu_input_map_linux_to_qnum_len) {
         return;
     }
-    qnum = qemu_input_map_qcode_to_qnum[q];
+    qnum = qemu_input_map_linux_to_qnum[lnx];
 
     if (down) {
         qemu_dbus_display1_keyboard_call_press(
diff --git a/ui/input-keymap.c b/ui/input-keymap.c
index 2f6d431c824..2b77ef09fd6 100644
--- a/ui/input-keymap.c
+++ b/ui/input-keymap.c
@@ -5,22 +5,36 @@
 #include "standard-headers/linux/input.h"
 
 #include "ui/input-keymap-atset1-to-qcode.c.inc"
+#include "ui/input-keymap-atset1-to-linux.c.inc"
 #include "ui/input-keymap-linux-to-qcode.c.inc"
 #include "ui/input-keymap-qcode-to-atset1.c.inc"
+#include "ui/input-keymap-linux-to-atset1.c.inc"
 #include "ui/input-keymap-qcode-to-atset2.c.inc"
+#include "ui/input-keymap-linux-to-atset2.c.inc"
 #include "ui/input-keymap-qcode-to-atset3.c.inc"
+#include "ui/input-keymap-linux-to-atset3.c.inc"
 #include "ui/input-keymap-qcode-to-linux.c.inc"
 #include "ui/input-keymap-qcode-to-qnum.c.inc"
+#include "ui/input-keymap-linux-to-qnum.c.inc"
 #include "ui/input-keymap-qcode-to-sun.c.inc"
+#include "ui/input-keymap-linux-to-sun.c.inc"
 #include "ui/input-keymap-qnum-to-qcode.c.inc"
+#include "ui/input-keymap-qnum-to-linux.c.inc"
 #include "ui/input-keymap-usb-to-qcode.c.inc"
+#include "ui/input-keymap-usb-to-linux.c.inc"
 #include "ui/input-keymap-win32-to-qcode.c.inc"
+#include "ui/input-keymap-win32-to-linux.c.inc"
 #include "ui/input-keymap-x11-to-qcode.c.inc"
+#include "ui/input-keymap-x11-to-linux.c.inc"
 #include "ui/input-keymap-xorgevdev-to-qcode.c.inc"
 #include "ui/input-keymap-xorgkbd-to-qcode.c.inc"
+#include "ui/input-keymap-xorgkbd-to-linux.c.inc"
 #include "ui/input-keymap-xorgxquartz-to-qcode.c.inc"
+#include "ui/input-keymap-xorgxquartz-to-linux.c.inc"
 #include "ui/input-keymap-xorgxwin-to-qcode.c.inc"
+#include "ui/input-keymap-xorgxwin-to-linux.c.inc"
 #include "ui/input-keymap-osx-to-qcode.c.inc"
+#include "ui/input-keymap-osx-to-linux.c.inc"
 
 int qemu_input_linux_to_qcode(unsigned int lnx)
 {
@@ -45,29 +59,49 @@ int qemu_input_key_value_to_number(const KeyValue *value)
 
 int qemu_input_key_number_to_qcode(unsigned int nr)
 {
-    if (nr >= qemu_input_map_qnum_to_qcode_len) {
-        return 0;
+    return qemu_input_linux_to_qcode(qemu_input_key_number_to_linux(nr));
+}
+
+unsigned int qemu_input_key_number_to_linux(unsigned int nr)
+{
+    if (nr >= qemu_input_map_qnum_to_linux_len) {
+        return KEY_RESERVED;
     }
-    return qemu_input_map_qnum_to_qcode[nr];
+    return qemu_input_map_qnum_to_linux[nr];
 }
 
 int qemu_input_key_value_to_qcode(const KeyValue *value)
 {
-    if (value->type == KEY_VALUE_KIND_QCODE) {
-        return value->u.qcode.data;
-    } else {
-        assert(value->type == KEY_VALUE_KIND_NUMBER);
-        return qemu_input_key_number_to_qcode(value->u.number.data);
+    return qemu_input_linux_to_qcode(qemu_input_key_value_to_linux(value));
+}
+
+unsigned int qemu_input_key_value_to_linux(const KeyValue *value)
+{
+    switch (value->type) {
+    case KEY_VALUE_KIND_NUMBER:
+        return qemu_input_key_number_to_linux(value->u.number.data);
+
+    case KEY_VALUE_KIND_QCODE:
+        return qemu_input_map_qcode_to_linux[value->u.qcode.data];
+
+    default:
+        g_assert_not_reached();
     }
 }
 
 int qemu_input_qcode_to_scancode(QKeyCode qcode, bool down, int *codes)
 {
-    int keycode = qcode < qemu_input_map_qcode_to_qnum_len ?
-                  qemu_input_map_qcode_to_qnum[qcode] : 0;
+    return qemu_input_linux_to_scancode(qemu_input_map_qcode_to_linux[qcode],
+                                        down, codes);
+}
+
+int qemu_input_linux_to_scancode(unsigned int lnx, bool down, int *codes)
+{
+    int keycode = lnx < qemu_input_map_linux_to_qnum_len ?
+                  qemu_input_map_linux_to_qnum[lnx] : 0;
     int count = 0;
 
-    if (qcode == Q_KEY_CODE_PAUSE) {
+    if (lnx == KEY_PAUSE) {
         /* specific case */
         int v = down ? 0 : 0x80;
         codes[count++] = 0xe1;
diff --git a/ui/input.c b/ui/input.c
index 9232dd7fdae..aeb7bf35e19 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -165,25 +165,10 @@ void qmp_input_send_event(const char *device,
         evt.type = qapi->type;
 
         switch (qapi->type) {
-        case INPUT_EVENT_KIND_KEY: {
-            KeyValue *key = qapi->u.key.data->key;
-            QKeyCode code;
-
-            switch (key->type) {
-            case KEY_VALUE_KIND_NUMBER:
-                code = qemu_input_key_number_to_qcode(key->u.number.data);
-                break;
-            case KEY_VALUE_KIND_QCODE:
-                code = key->u.qcode.data;
-                break;
-            default:
-                g_assert_not_reached();
-            }
-
-            evt.key.key = code;
+        case INPUT_EVENT_KIND_KEY:
+            evt.key.key = qemu_input_key_value_to_linux(qapi->u.key.data->key);
             evt.key.down = qapi->u.key.data->down;
             break;
-        }
 
         case INPUT_EVENT_KIND_BTN:
             evt.btn = *qapi->u.btn.data;
@@ -226,7 +211,7 @@ static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
         key = &evt->key;
-        name = QKeyCode_str(key->key);
+        name = QKeyCode_str(qemu_input_linux_to_qcode(key->key));
         trace_input_event_key_qcode(idx, name, key->down);
         break;
     case INPUT_EVENT_KIND_BTN:
@@ -343,19 +328,6 @@ void qemu_input_event_send_impl(QemuConsole *src, QemuInputEvent *evt)
 
 void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
 {
-    /*
-     * 'sysrq' was mistakenly added to hack around the fact that
-     * the ps2 driver was not generating correct scancodes sequences
-     * when 'alt+print' was pressed. This flaw is now fixed and the
-     * 'sysrq' key serves no further purpose. We normalize it to
-     * 'print', so that downstream receivers of the event don't
-     * need to deal with this mistake
-     */
-    if (evt->type == INPUT_EVENT_KIND_KEY &&
-        evt->key.key == Q_KEY_CODE_SYSRQ) {
-        evt->key.key = Q_KEY_CODE_PRINT;
-    }
-
     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
         return;
     }
@@ -390,17 +362,24 @@ void qemu_input_event_sync(void)
 }
 
 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
+{
+    unsigned int lnx = qemu_input_key_value_to_linux(key);
+
+    g_free(key);
+    qemu_input_event_send_key_linux(src, lnx, down);
+}
+
+void qemu_input_event_send_key_linux(QemuConsole *src, unsigned int lnx,
+                                     bool down)
 {
     QemuInputEvent evt = {
         .type = INPUT_EVENT_KIND_KEY,
         .key = {
-            .key = qemu_input_key_value_to_qcode(key),
+            .key = lnx,
             .down = down,
         },
     };
 
-    g_free(key);
-
     if (QTAILQ_EMPTY(&kbd_queue)) {
         qemu_input_event_send(src, &evt);
         qemu_input_event_sync();
@@ -412,8 +391,8 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
 
 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
 {
-    QKeyCode code = qemu_input_key_number_to_qcode(num);
-    qemu_input_event_send_key_qcode(src, code, down);
+    unsigned int lnx = qemu_input_key_number_to_linux(num);
+    qemu_input_event_send_key_linux(src, lnx, down);
 }
 
 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
diff --git a/tools/qemu-vnc/trace-events b/tools/qemu-vnc/trace-events
index e3b550de10e..570062984a4 100644
--- a/tools/qemu-vnc/trace-events
+++ b/tools/qemu-vnc/trace-events
@@ -12,7 +12,7 @@ qemu_vnc_cursor_define(int width, int height, int hot_x, int hot_y) "w=%d h=%d h
 qemu_vnc_input_abs(uint32_t x, uint32_t y) "x=%u y=%u"
 qemu_vnc_input_btn(int button, bool press) "button=%d press=%d"
 qemu_vnc_input_rel(int dx, int dy) "dx=%d dy=%d"
-qemu_vnc_key_event(int qcode, bool down) "qcode=%d down=%d"
+qemu_vnc_key_event(unsigned int lnx, bool down) "lnx=%u down=%d"
 qemu_vnc_owner_appeared(const char *name) "peer=%s"
 qemu_vnc_owner_vanished(const char *name) "peer=%s"
 qemu_vnc_scanout(uint32_t width, uint32_t height, uint32_t stride, uint32_t format) "w=%u h=%u stride=%u fmt=0x%x"
diff --git a/ui/meson.build b/ui/meson.build
index 1b8f71796e4..1504e27248f 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -1,21 +1,35 @@
 keymaps = [
   ['atset1', 'qcode'],
+  ['atset1', 'linux'],
   ['linux', 'qcode'],
   ['qcode', 'atset1'],
+  ['linux', 'atset1'],
   ['qcode', 'atset2'],
+  ['linux', 'atset2'],
   ['qcode', 'atset3'],
+  ['linux', 'atset3'],
   ['qcode', 'linux'],
   ['qcode', 'qnum'],
+  ['linux', 'qnum'],
   ['qcode', 'sun'],
+  ['linux', 'sun'],
   ['qnum', 'qcode'],
+  ['qnum', 'linux'],
   ['usb', 'qcode'],
+  ['usb', 'linux'],
   ['win32', 'qcode'],
+  ['win32', 'linux'],
   ['x11', 'qcode'],
+  ['x11', 'linux'],
   ['xorgevdev', 'qcode'],
   ['xorgkbd', 'qcode'],
+  ['xorgkbd', 'linux'],
   ['xorgxquartz', 'qcode'],
+  ['xorgxquartz', 'linux'],
   ['xorgxwin', 'qcode'],
+  ['xorgxwin', 'linux'],
   ['osx', 'qcode'],
+  ['osx', 'linux'],
 ]
 
 if have_system or xkbcommon.found()
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 13/38] ui/input: Prohibit sending KEY_RESERVED
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (11 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 12/38] ui/input: Use Linux key codes for internal key events marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 14/38] ui/console: Add qemu_text_console_put_linux() marcandre.lureau
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

xenfb and virtio-input no longer need key mapping because they operate
on Linux key codes, but removing the key mapping code loses the ability
to filter out KEY_RESERVED. Drop KEY_RESERVED at the common input event
entry point so the logic is shared by both devices and no downstream
input handler receives KEY_RESERVED accidentally.

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-5-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/input.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ui/input.c b/ui/input.c
index aeb7bf35e19..68c7ac6f1cc 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -328,6 +328,10 @@ void qemu_input_event_send_impl(QemuConsole *src, QemuInputEvent *evt)
 
 void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
 {
+    if (evt->type == INPUT_EVENT_KIND_KEY && !evt->key.key) {
+        return;
+    }
+
     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
         return;
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 14/38] ui/console: Add qemu_text_console_put_linux()
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (12 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 13/38] ui/input: Prohibit sending KEY_RESERVED marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 15/38] ui/kbd-state: Use Linux key codes marcandre.lureau
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

Add a text console helper that accepts Linux input key codes and use it
as the common implementation for qemu_text_console_put_qcode(). This lets
callers that already use Linux key codes avoid converting them back to
QKeyCode.

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-6-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 include/ui/console.h |  2 ++
 ui/console.c         | 66 +++++++++++++++++++++++++++++---------------
 2 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index cfa940d4c66..691040f5948 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -109,6 +109,8 @@ bool qemu_mouse_set(int index, Error **errp);
 
 void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym);
 bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl);
+bool qemu_text_console_put_linux(QemuTextConsole *s, unsigned int lnx,
+                                 bool ctrl);
 void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len);
 
 /* consoles */
diff --git a/ui/console.c b/ui/console.c
index eaa41086743..2dcb4660fbf 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "ui/vgafont.h"
 #include "hw/core/qdev.h"
@@ -302,36 +303,57 @@ void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
     qemu_text_console_handle_keysym(s, keysym);
 }
 
-static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
-    [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
-    [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
-    [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
-    [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
-    [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
-    [Q_KEY_CODE_END]    = QEMU_KEY_END,
-    [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
-    [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
-    [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
-    [Q_KEY_CODE_TAB]    = QEMU_KEY_TAB,
-    [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
+static const int linux_to_keysym[] = {
+    [KEY_UP]     = QEMU_KEY_UP,
+    [KEY_DOWN]   = QEMU_KEY_DOWN,
+    [KEY_RIGHT]  = QEMU_KEY_RIGHT,
+    [KEY_LEFT]   = QEMU_KEY_LEFT,
+    [KEY_HOME]   = QEMU_KEY_HOME,
+    [KEY_END]    = QEMU_KEY_END,
+    [KEY_PAGEUP]   = QEMU_KEY_PAGEUP,
+    [KEY_PAGEDOWN]   = QEMU_KEY_PAGEDOWN,
+    [KEY_DELETE] = QEMU_KEY_DELETE,
+    [KEY_TAB]    = QEMU_KEY_TAB,
+    [KEY_BACKSPACE] = QEMU_KEY_BACKSPACE,
 };
 
-static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
-    [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
-    [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
-    [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
-    [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
-    [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
-    [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
-    [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
-    [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
+static const int ctrl_linux_to_keysym[] = {
+    [KEY_UP]     = QEMU_KEY_CTRL_UP,
+    [KEY_DOWN]   = QEMU_KEY_CTRL_DOWN,
+    [KEY_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
+    [KEY_LEFT]   = QEMU_KEY_CTRL_LEFT,
+    [KEY_HOME]   = QEMU_KEY_CTRL_HOME,
+    [KEY_END]    = QEMU_KEY_CTRL_END,
+    [KEY_PAGEUP]   = QEMU_KEY_CTRL_PAGEUP,
+    [KEY_PAGEDOWN]   = QEMU_KEY_CTRL_PAGEDOWN,
 };
 
 bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl)
 {
+    unsigned int lnx = qemu_input_map_qcode_to_linux[qcode];
+    return qemu_text_console_put_linux(s, lnx, ctrl);
+}
+
+bool qemu_text_console_put_linux(QemuTextConsole *s, unsigned int lnx,
+                                 bool ctrl)
+{
+    size_t maplen;
+    const int *map;
     int keysym;
 
-    keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
+    if (ctrl) {
+        maplen = ARRAY_SIZE(ctrl_linux_to_keysym);
+        map = ctrl_linux_to_keysym;
+    } else {
+        maplen = ARRAY_SIZE(linux_to_keysym);
+        map = linux_to_keysym;
+    }
+
+    if (lnx >= maplen) {
+        return false;
+    }
+
+    keysym = map[lnx];
     if (keysym == 0) {
         return false;
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 15/38] ui/kbd-state: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (13 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 14/38] ui/console: Add qemu_text_console_put_linux() marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:31 ` [PULL v3 16/38] hw/arm/musicpal: " marcandre.lureau
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Marc-André Lureau, Peter Maydell,
	Philippe Mathieu-Daudé

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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>
---
 include/ui/kbd-state.h | 12 ++++----
 ui/dbus-console.c      |  4 +--
 ui/gtk.c               |  7 +++--
 ui/kbd-state.c         | 61 +++++++++++++++++++++-----------------
 ui/keymaps.c           |  3 +-
 ui/sdl2-input.c        |  3 +-
 ui/vnc.c               | 10 +++++--
 ui/cocoa.m             | 67 +++++++++++++++++++++++++++++++-----------
 8 files changed, 108 insertions(+), 59 deletions(-)

diff --git a/include/ui/kbd-state.h b/include/ui/kbd-state.h
index 1f37b932eb6..a70d5b5746b 100644
--- a/include/ui/kbd-state.h
+++ b/include/ui/kbd-state.h
@@ -52,11 +52,13 @@ void qkbd_state_free(QKbdState *kbd);
  * This function takes care to not send suspious events (keyup event
  * for a key not pressed for example).
  *
+ * This function drops events with key codes outside the defined range.
+ *
  * @kbd: state tracker state.
- * @qcode: the key pressed or released.
+ * @lnx: the key pressed or released.
  * @down: true for key down events, false otherwise.
  */
-void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down);
+void qkbd_state_key_event(QKbdState *kbd, unsigned int lnx, bool down);
 
 /**
  * qkbd_state_set_delay: set key press delay.
@@ -72,12 +74,12 @@ void qkbd_state_set_delay(QKbdState *kbd, int delay_ms);
 /**
  * qkbd_state_key_get: get key state.
  *
- * Returns true when the key is down.
+ * Returns true when the key code is in the defined range and the key is down.
  *
  * @kbd: state tracker state.
- * @qcode: the key to query.
+ * @lnx: the key to query.
  */
-bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode);
+bool qkbd_state_key_get(QKbdState *kbd, unsigned int lnx);
 
 /**
  * qkbd_state_modifier_get: get modifier state.
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index b8e5c57b148..24f4542f312 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -343,7 +343,7 @@ dbus_kbd_press(DBusDisplayConsole *ddc,
 
     trace_dbus_kbd_press(arg_keycode);
 
-    qkbd_state_key_event(ddc->kbd, qcode, true);
+    qkbd_state_key_event(ddc->kbd, qemu_input_map_qcode_to_linux[qcode], true);
 
     qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation);
 
@@ -359,7 +359,7 @@ dbus_kbd_release(DBusDisplayConsole *ddc,
 
     trace_dbus_kbd_release(arg_keycode);
 
-    qkbd_state_key_event(ddc->kbd, qcode, false);
+    qkbd_state_key_event(ddc->kbd, qemu_input_map_qcode_to_linux[qcode], false);
 
     qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation);
 
diff --git a/ui/gtk.c b/ui/gtk.c
index 2c61b601f78..757ee80fa6a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1343,7 +1343,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
         || key->hardware_keycode == VK_PAUSE
 #endif
         ) {
-        qkbd_state_key_event(vc->gfx.kbd, Q_KEY_CODE_PAUSE,
+        qkbd_state_key_event(vc->gfx.kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_PAUSE],
                              key->type == GDK_KEY_PRESS);
         return TRUE;
     }
@@ -1351,10 +1352,10 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
     keycode = gd_get_keycode(key);
     qcode = gd_map_keycode(keycode);
 
-    trace_gd_key_event(vc->label, keycode, qcode,
+    trace_gd_key_event(vc->label, keycode, qemu_input_map_qcode_to_linux[qcode],
                        (key->type == GDK_KEY_PRESS) ? "down" : "up");
 
-    qkbd_state_key_event(vc->gfx.kbd, qcode,
+    qkbd_state_key_event(vc->gfx.kbd, qemu_input_map_qcode_to_linux[qcode],
                          key->type == GDK_KEY_PRESS);
 
     return TRUE;
diff --git a/ui/kbd-state.c b/ui/kbd-state.c
index 52ed28b8a89..c407327da59 100644
--- a/ui/kbd-state.c
+++ b/ui/kbd-state.c
@@ -5,6 +5,7 @@
  */
 #include "qemu/osdep.h"
 #include "qemu/bitmap.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "ui/input.h"
 #include "ui/kbd-state.h"
@@ -12,15 +13,15 @@
 struct QKbdState {
     QemuConsole *con;
     int key_delay_ms;
-    DECLARE_BITMAP(keys, Q_KEY_CODE__MAX);
+    DECLARE_BITMAP(keys, KEY_CNT);
     DECLARE_BITMAP(mods, QKBD_MOD__MAX);
 };
 
 static void qkbd_state_modifier_update(QKbdState *kbd,
-                                      QKeyCode qcode1, QKeyCode qcode2,
+                                       unsigned int lnx1, unsigned int lnx2,
                                       QKbdModifier mod)
 {
-    if (test_bit(qcode1, kbd->keys) || test_bit(qcode2, kbd->keys)) {
+    if (test_bit(lnx1, kbd->keys) || test_bit(lnx2, kbd->keys)) {
         set_bit(mod, kbd->mods);
     } else {
         clear_bit(mod, kbd->mods);
@@ -32,14 +33,20 @@ bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod)
     return test_bit(mod, kbd->mods);
 }
 
-bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode)
+bool qkbd_state_key_get(QKbdState *kbd, unsigned int lnx)
 {
-    return test_bit(qcode, kbd->keys);
+    return lnx < KEY_CNT && test_bit(lnx, kbd->keys);
 }
 
-void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
+void qkbd_state_key_event(QKbdState *kbd, unsigned int lnx, bool down)
 {
-    bool state = test_bit(qcode, kbd->keys);
+    bool state;
+
+    if (lnx >= KEY_CNT) {
+        return;
+    }
+
+    state = test_bit(lnx, kbd->keys);
 
     if (down == false  /* got key-up event   */ &&
         state == false /* key is not pressed */) {
@@ -59,35 +66,35 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
 
     /* update key and modifier state */
     if (down) {
-        set_bit(qcode, kbd->keys);
+        set_bit(lnx, kbd->keys);
     } else {
-        clear_bit(qcode, kbd->keys);
+        clear_bit(lnx, kbd->keys);
     }
-    switch (qcode) {
-    case Q_KEY_CODE_SHIFT:
-    case Q_KEY_CODE_SHIFT_R:
-        qkbd_state_modifier_update(kbd, Q_KEY_CODE_SHIFT, Q_KEY_CODE_SHIFT_R,
+    switch (lnx) {
+    case KEY_LEFTSHIFT:
+    case KEY_RIGHTSHIFT:
+        qkbd_state_modifier_update(kbd, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
                                    QKBD_MOD_SHIFT);
         break;
-    case Q_KEY_CODE_CTRL:
-    case Q_KEY_CODE_CTRL_R:
-        qkbd_state_modifier_update(kbd, Q_KEY_CODE_CTRL, Q_KEY_CODE_CTRL_R,
+    case KEY_LEFTCTRL:
+    case KEY_RIGHTCTRL:
+        qkbd_state_modifier_update(kbd, KEY_LEFTCTRL, KEY_RIGHTCTRL,
                                    QKBD_MOD_CTRL);
         break;
-    case Q_KEY_CODE_ALT:
-        qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT, Q_KEY_CODE_ALT,
+    case KEY_LEFTALT:
+        qkbd_state_modifier_update(kbd, KEY_LEFTALT, KEY_LEFTALT,
                                    QKBD_MOD_ALT);
         break;
-    case Q_KEY_CODE_ALT_R:
-        qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT_R, Q_KEY_CODE_ALT_R,
+    case KEY_RIGHTALT:
+        qkbd_state_modifier_update(kbd, KEY_RIGHTALT, KEY_RIGHTALT,
                                    QKBD_MOD_ALTGR);
         break;
-    case Q_KEY_CODE_CAPS_LOCK:
+    case KEY_CAPSLOCK:
         if (down) {
             change_bit(QKBD_MOD_CAPSLOCK, kbd->mods);
         }
         break;
-    case Q_KEY_CODE_NUM_LOCK:
+    case KEY_NUMLOCK:
         if (down) {
             change_bit(QKBD_MOD_NUMLOCK, kbd->mods);
         }
@@ -99,7 +106,7 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
 
     /* send to guest */
     if (qemu_console_is_graphic(kbd->con)) {
-        qemu_input_event_send_key_qcode(kbd->con, qcode, down);
+        qemu_input_event_send_key_linux(kbd->con, lnx, down);
         if (kbd->key_delay_ms) {
             qemu_input_event_send_key_delay(kbd->key_delay_ms);
         }
@@ -108,11 +115,11 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
 
 void qkbd_state_lift_all_keys(QKbdState *kbd)
 {
-    int qcode;
+    unsigned int lnx;
 
-    for (qcode = 0; qcode < Q_KEY_CODE__MAX; qcode++) {
-        if (test_bit(qcode, kbd->keys)) {
-            qkbd_state_key_event(kbd, qcode, false);
+    for (lnx = 0; lnx < KEY_CNT; lnx++) {
+        if (test_bit(lnx, kbd->keys)) {
+            qkbd_state_key_event(kbd, lnx, false);
         }
     }
 }
diff --git a/ui/keymaps.c b/ui/keymaps.c
index 6822c097be7..a448efab320 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -257,7 +257,8 @@ int keysym2scancode(kbd_layout_t *k, int keysym,
         for (i = 0; i < keysym2code->count; i++) {
             QKeyCode qcode = qemu_input_key_number_to_qcode
                 (keysym2code->keycodes[i]);
-            if (kbd && qkbd_state_key_get(kbd, qcode)) {
+            unsigned int lnx = qemu_input_map_qcode_to_linux[qcode];
+            if (kbd && qkbd_state_key_get(kbd, lnx)) {
                 return keysym2code->keycodes[i];
             }
         }
diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c
index 2286df4223d..fdbdc427dc9 100644
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -41,7 +41,8 @@ void sdl2_process_key(struct sdl2_console *scon,
     qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode];
     trace_sdl2_process_key(ev->keysym.scancode, qcode,
                            ev->type == SDL_KEYDOWN ? "down" : "up");
-    qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN);
+    qkbd_state_key_event(scon->kbd, qemu_input_map_qcode_to_linux[qcode],
+                         ev->type == SDL_KEYDOWN);
 
     if (QEMU_IS_TEXT_CONSOLE(con)) {
         QemuTextConsole *s = QEMU_TEXT_CONSOLE(con);
diff --git a/ui/vnc.c b/ui/vnc.c
index 2159bb35d54..0a8c5ab0d2d 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1799,8 +1799,11 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
 
 static void press_key(VncState *vs, QKeyCode qcode)
 {
-    qkbd_state_key_event(vs->vd->kbd, qcode, true);
-    qkbd_state_key_event(vs->vd->kbd, qcode, false);
+    qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
+                         true);
+
+    qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
+                         false);
 }
 
 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)
         }
     }
 
-    qkbd_state_key_event(vs->vd->kbd, qcode, down);
+    qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
+                         down);
     if (QEMU_IS_TEXT_CONSOLE(vs->vd->dcl.con)) {
         QemuTextConsole *con = QEMU_TEXT_CONSOLE(vs->vd->dcl.con);
         bool numlock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK);
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 98394cdc507..ee53e7c72ed 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -767,7 +767,8 @@ - (void) setFullGrab:(id)sender
 }
 
 - (void) toggleKey: (int)keycode {
-    qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode));
+    unsigned int lnx = qemu_input_map_qcode_to_linux[keycode];
+    qkbd_state_key_event(kbd, lnx, !qkbd_state_key_get(kbd, lnx));
 }
 
 // Does the work of sending input to the monitor
@@ -889,34 +890,62 @@ - (bool) handleEventLocked:(NSEvent *)event
      */
     if (!!(modifiers & NSEventModifierFlagCapsLock) !=
         qkbd_state_modifier_get(kbd, QKBD_MOD_CAPSLOCK)) {
-        qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, true);
-        qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, false);
+        qkbd_state_key_event(kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CAPS_LOCK],
+                             true);
+        qkbd_state_key_event(kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CAPS_LOCK],
+                             false);
     }
 
     if (!(modifiers & NSEventModifierFlagShift)) {
-        qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT, false);
-        qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT_R, false);
+        qkbd_state_key_event(kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_SHIFT],
+                             false);
+        qkbd_state_key_event(kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_SHIFT_R],
+                             false);
     }
     if (!(modifiers & NSEventModifierFlagControl)) {
-        qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL, false);
-        qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL_R, false);
+        qkbd_state_key_event(kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CTRL],
+                             false);
+        qkbd_state_key_event(kbd,
+                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CTRL_R],
+                             false);
     }
     if (!(modifiers & NSEventModifierFlagOption)) {
         if (swap_opt_cmd) {
-            qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
-            qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_L],
+                                 false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_R],
+                                 false);
         } else {
-            qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
-            qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT],
+                                 false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT_R],
+                                 false);
         }
     }
     if (!(modifiers & NSEventModifierFlagCommand)) {
         if (swap_opt_cmd) {
-            qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
-            qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT],
+                                 false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT_R],
+                                 false);
         } else {
-            qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
-            qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_L],
+                                 false);
+            qkbd_state_key_event(kbd,
+                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_R],
+                                 false);
         }
     }
 
@@ -1023,7 +1052,9 @@ - (bool) handleEventLocked:(NSEvent *)event
             }
 
             if (qemu_console_is_graphic(dcl.con)) {
-                qkbd_state_key_event(kbd, keycode, true);
+                qkbd_state_key_event(kbd,
+                                     qemu_input_map_qcode_to_linux[keycode],
+                                     true);
             } else {
                 [self handleMonitorInput: event];
             }
@@ -1038,7 +1069,9 @@ - (bool) handleEventLocked:(NSEvent *)event
             }
 
             if (qemu_console_is_graphic(dcl.con)) {
-                qkbd_state_key_event(kbd, keycode, false);
+                qkbd_state_key_event(kbd,
+                                     qemu_input_map_qcode_to_linux[keycode],
+                                     false);
             }
             return true;
         case NSEventTypeScrollWheel:
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 16/38] hw/arm/musicpal: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (14 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 15/38] ui/kbd-state: Use Linux key codes marcandre.lureau
@ 2026-05-25  6:31 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 17/38] hw/char/escc: " marcandre.lureau
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Jan Kiszka, Peter Maydell,
	open list:Musicpal

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-8-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/arm/musicpal.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index c8985a58f99..e2630243eb7 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -24,6 +24,7 @@
 #include "hw/core/ptimer.h"
 #include "hw/core/qdev-properties.h"
 #include "hw/block/flash.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "hw/i2c/i2c.h"
 #include "hw/i2c/bitbang_i2c.h"
@@ -1069,40 +1070,39 @@ static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     musicpal_key_state *s = MUSICPAL_KEY(dev);
-    int qcode = qemu_input_linux_to_qcode(evt->key.key);
     uint32_t event = 0;
     int i;
 
-    switch (qcode) {
-    case Q_KEY_CODE_UP:
+    switch (evt->key.key) {
+    case KEY_UP:
         event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
         break;
 
-    case Q_KEY_CODE_DOWN:
+    case KEY_DOWN:
         event = MP_KEY_WHEEL_NAV;
         break;
 
-    case Q_KEY_CODE_LEFT:
+    case KEY_LEFT:
         event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
         break;
 
-    case Q_KEY_CODE_RIGHT:
+    case KEY_RIGHT:
         event = MP_KEY_WHEEL_VOL;
         break;
 
-    case Q_KEY_CODE_F:
+    case KEY_F:
         event = MP_KEY_BTN_FAVORITS;
         break;
 
-    case Q_KEY_CODE_TAB:
+    case KEY_TAB:
         event = MP_KEY_BTN_VOLUME;
         break;
 
-    case Q_KEY_CODE_RET:
+    case KEY_ENTER:
         event = MP_KEY_BTN_NAVIGATION;
         break;
 
-    case Q_KEY_CODE_M:
+    case KEY_M:
         event = MP_KEY_BTN_MENU;
         break;
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 17/38] hw/char/escc: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (15 preceding siblings ...)
  2026-05-25  6:31 ` [PULL v3 16/38] hw/arm/musicpal: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 18/38] hw/display/xenfb: " marcandre.lureau
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau, Paolo Bonzini

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-9-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/char/escc.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/hw/char/escc.c b/hw/char/escc.c
index 39483ca03bf..7aae627fb48 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -30,6 +30,7 @@
 #include "migration/vmstate.h"
 #include "qemu/module.h"
 #include "hw/char/escc.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 
 #include "qemu/cutils.h"
@@ -804,7 +805,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     trace_escc_sunkbd_event_in(qcode, QKeyCode_str(qcode),
                                evt->key.down);
 
-    if (qcode == Q_KEY_CODE_CAPS_LOCK) {
+    if (evt->key.key == KEY_CAPSLOCK) {
         if (evt->key.down) {
             s->caps_lock_mode ^= 1;
             if (s->caps_lock_mode == 2) {
@@ -818,7 +819,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
         }
     }
 
-    if (qcode == Q_KEY_CODE_NUM_LOCK) {
+    if (evt->key.key == KEY_NUMLOCK) {
         if (evt->key.down) {
             s->num_lock_mode ^= 1;
             if (s->num_lock_mode == 2) {
@@ -832,11 +833,11 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
         }
     }
 
-    if (qcode >= qemu_input_map_qcode_to_sun_len) {
+    if (evt->key.key >= qemu_input_map_linux_to_sun_len) {
         return;
     }
 
-    keycode = qemu_input_map_qcode_to_sun[qcode];
+    keycode = qemu_input_map_linux_to_sun[evt->key.key];
     if (!evt->key.down) {
         keycode |= 0x80;
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 18/38] hw/display/xenfb: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (16 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 17/38] hw/char/escc: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 19/38] hw/input/adb-kbd: " marcandre.lureau
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Stefano Stabellini, Anthony PERARD,
	Edgar E. Iglesias, open list:X86 Xen CPUs

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-10-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/display/xenfb.c | 21 +++------------------
 1 file changed, 3 insertions(+), 18 deletions(-)

diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 218f37f0740..ae302b217fe 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -191,29 +191,14 @@ static int xenfb_send_position(struct XenInput *xenfb,
     return xenfb_kbd_event(xenfb, &event);
 }
 
-/*
- * Send a key event from the client to the guest OS
- * QEMU gives us a QCode.
- * We have to turn this into a Linux Input layer keycode.
- *
- * Wish we could just send scancodes straight to the guest which
- * already has code for dealing with this...
- */
+/* Send a key event from the client to the guest OS */
 static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
                             QemuInputEvent *evt)
 {
     struct XenInput *xenfb = (struct XenInput *)dev;
-    int qcode = qemu_input_linux_to_qcode(evt->key.key);
-    int lnx;
 
-    if (qcode < qemu_input_map_qcode_to_linux_len) {
-        lnx = qemu_input_map_qcode_to_linux[qcode];
-
-        if (lnx) {
-            trace_xenfb_key_event(xenfb, lnx, evt->key.down);
-            xenfb_send_key(xenfb, evt->key.down, lnx);
-        }
-    }
+    trace_xenfb_key_event(xenfb, evt->key.key, evt->key.down);
+    xenfb_send_key(xenfb, evt->key.down, evt->key.key);
 }
 
 /*
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 19/38] hw/input/adb-kbd: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (17 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 18/38] hw/display/xenfb: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 20/38] hw/input/hid: " marcandre.lureau
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Mark Cave-Ayland,
	open list:Old World (g3beige)

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-11-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/input/adb-kbd.c | 242 ++++++++++++++++++++++-----------------------
 1 file changed, 120 insertions(+), 122 deletions(-)

diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 060481d0db6..c4ef9ebb90c 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -26,6 +26,7 @@
 #include "hw/input/adb.h"
 #include "migration/vmstate.h"
 #include "qemu/module.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/input.h"
 #include "hw/input/adb-keys.h"
 #include "adb-internal.h"
@@ -55,124 +56,122 @@ struct ADBKeyboardClass {
 /* The adb keyboard doesn't have every key imaginable */
 #define NO_KEY 0xff
 
-int qcode_to_adb_keycode[] = {
+int linux_to_adb_keycode[] = {
      /* Make sure future additions are automatically set to NO_KEY */
-    [0 ... 0xff]               = NO_KEY,
-
-    [Q_KEY_CODE_SHIFT]         = ADB_KEY_LEFT_SHIFT,
-    [Q_KEY_CODE_SHIFT_R]       = ADB_KEY_RIGHT_SHIFT,
-    [Q_KEY_CODE_ALT]           = ADB_KEY_LEFT_OPTION,
-    [Q_KEY_CODE_ALT_R]         = ADB_KEY_RIGHT_OPTION,
-    [Q_KEY_CODE_CTRL]          = ADB_KEY_LEFT_CONTROL,
-    [Q_KEY_CODE_CTRL_R]        = ADB_KEY_RIGHT_CONTROL,
-    [Q_KEY_CODE_META_L]        = ADB_KEY_COMMAND,
-    [Q_KEY_CODE_META_R]        = ADB_KEY_COMMAND,
-    [Q_KEY_CODE_SPC]           = ADB_KEY_SPACEBAR,
-
-    [Q_KEY_CODE_ESC]           = ADB_KEY_ESC,
-    [Q_KEY_CODE_1]             = ADB_KEY_1,
-    [Q_KEY_CODE_2]             = ADB_KEY_2,
-    [Q_KEY_CODE_3]             = ADB_KEY_3,
-    [Q_KEY_CODE_4]             = ADB_KEY_4,
-    [Q_KEY_CODE_5]             = ADB_KEY_5,
-    [Q_KEY_CODE_6]             = ADB_KEY_6,
-    [Q_KEY_CODE_7]             = ADB_KEY_7,
-    [Q_KEY_CODE_8]             = ADB_KEY_8,
-    [Q_KEY_CODE_9]             = ADB_KEY_9,
-    [Q_KEY_CODE_0]             = ADB_KEY_0,
-    [Q_KEY_CODE_MINUS]         = ADB_KEY_MINUS,
-    [Q_KEY_CODE_EQUAL]         = ADB_KEY_EQUAL,
-    [Q_KEY_CODE_BACKSPACE]     = ADB_KEY_DELETE,
-    [Q_KEY_CODE_TAB]           = ADB_KEY_TAB,
-    [Q_KEY_CODE_Q]             = ADB_KEY_Q,
-    [Q_KEY_CODE_W]             = ADB_KEY_W,
-    [Q_KEY_CODE_E]             = ADB_KEY_E,
-    [Q_KEY_CODE_R]             = ADB_KEY_R,
-    [Q_KEY_CODE_T]             = ADB_KEY_T,
-    [Q_KEY_CODE_Y]             = ADB_KEY_Y,
-    [Q_KEY_CODE_U]             = ADB_KEY_U,
-    [Q_KEY_CODE_I]             = ADB_KEY_I,
-    [Q_KEY_CODE_O]             = ADB_KEY_O,
-    [Q_KEY_CODE_P]             = ADB_KEY_P,
-    [Q_KEY_CODE_BRACKET_LEFT]  = ADB_KEY_LEFT_BRACKET,
-    [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET,
-    [Q_KEY_CODE_RET]           = ADB_KEY_RETURN,
-    [Q_KEY_CODE_A]             = ADB_KEY_A,
-    [Q_KEY_CODE_S]             = ADB_KEY_S,
-    [Q_KEY_CODE_D]             = ADB_KEY_D,
-    [Q_KEY_CODE_F]             = ADB_KEY_F,
-    [Q_KEY_CODE_G]             = ADB_KEY_G,
-    [Q_KEY_CODE_H]             = ADB_KEY_H,
-    [Q_KEY_CODE_J]             = ADB_KEY_J,
-    [Q_KEY_CODE_K]             = ADB_KEY_K,
-    [Q_KEY_CODE_L]             = ADB_KEY_L,
-    [Q_KEY_CODE_SEMICOLON]     = ADB_KEY_SEMICOLON,
-    [Q_KEY_CODE_APOSTROPHE]    = ADB_KEY_APOSTROPHE,
-    [Q_KEY_CODE_GRAVE_ACCENT]  = ADB_KEY_GRAVE_ACCENT,
-    [Q_KEY_CODE_BACKSLASH]     = ADB_KEY_BACKSLASH,
-    [Q_KEY_CODE_Z]             = ADB_KEY_Z,
-    [Q_KEY_CODE_X]             = ADB_KEY_X,
-    [Q_KEY_CODE_C]             = ADB_KEY_C,
-    [Q_KEY_CODE_V]             = ADB_KEY_V,
-    [Q_KEY_CODE_B]             = ADB_KEY_B,
-    [Q_KEY_CODE_N]             = ADB_KEY_N,
-    [Q_KEY_CODE_M]             = ADB_KEY_M,
-    [Q_KEY_CODE_COMMA]         = ADB_KEY_COMMA,
-    [Q_KEY_CODE_DOT]           = ADB_KEY_PERIOD,
-    [Q_KEY_CODE_SLASH]         = ADB_KEY_FORWARD_SLASH,
-    [Q_KEY_CODE_ASTERISK]      = ADB_KEY_KP_MULTIPLY,
-    [Q_KEY_CODE_CAPS_LOCK]     = ADB_KEY_CAPS_LOCK,
-
-    [Q_KEY_CODE_F1]            = ADB_KEY_F1,
-    [Q_KEY_CODE_F2]            = ADB_KEY_F2,
-    [Q_KEY_CODE_F3]            = ADB_KEY_F3,
-    [Q_KEY_CODE_F4]            = ADB_KEY_F4,
-    [Q_KEY_CODE_F5]            = ADB_KEY_F5,
-    [Q_KEY_CODE_F6]            = ADB_KEY_F6,
-    [Q_KEY_CODE_F7]            = ADB_KEY_F7,
-    [Q_KEY_CODE_F8]            = ADB_KEY_F8,
-    [Q_KEY_CODE_F9]            = ADB_KEY_F9,
-    [Q_KEY_CODE_F10]           = ADB_KEY_F10,
-    [Q_KEY_CODE_F11]           = ADB_KEY_F11,
-    [Q_KEY_CODE_F12]           = ADB_KEY_F12,
-    [Q_KEY_CODE_PRINT]         = ADB_KEY_F13,
-    [Q_KEY_CODE_SYSRQ]         = ADB_KEY_F13,
-    [Q_KEY_CODE_SCROLL_LOCK]   = ADB_KEY_F14,
-    [Q_KEY_CODE_PAUSE]         = ADB_KEY_F15,
-
-    [Q_KEY_CODE_NUM_LOCK]      = ADB_KEY_KP_CLEAR,
-    [Q_KEY_CODE_KP_EQUALS]     = ADB_KEY_KP_EQUAL,
-    [Q_KEY_CODE_KP_DIVIDE]     = ADB_KEY_KP_DIVIDE,
-    [Q_KEY_CODE_KP_MULTIPLY]   = ADB_KEY_KP_MULTIPLY,
-    [Q_KEY_CODE_KP_SUBTRACT]   = ADB_KEY_KP_SUBTRACT,
-    [Q_KEY_CODE_KP_ADD]        = ADB_KEY_KP_PLUS,
-    [Q_KEY_CODE_KP_ENTER]      = ADB_KEY_KP_ENTER,
-    [Q_KEY_CODE_KP_DECIMAL]    = ADB_KEY_KP_PERIOD,
-    [Q_KEY_CODE_KP_0]          = ADB_KEY_KP_0,
-    [Q_KEY_CODE_KP_1]          = ADB_KEY_KP_1,
-    [Q_KEY_CODE_KP_2]          = ADB_KEY_KP_2,
-    [Q_KEY_CODE_KP_3]          = ADB_KEY_KP_3,
-    [Q_KEY_CODE_KP_4]          = ADB_KEY_KP_4,
-    [Q_KEY_CODE_KP_5]          = ADB_KEY_KP_5,
-    [Q_KEY_CODE_KP_6]          = ADB_KEY_KP_6,
-    [Q_KEY_CODE_KP_7]          = ADB_KEY_KP_7,
-    [Q_KEY_CODE_KP_8]          = ADB_KEY_KP_8,
-    [Q_KEY_CODE_KP_9]          = ADB_KEY_KP_9,
-
-    [Q_KEY_CODE_UP]            = ADB_KEY_UP,
-    [Q_KEY_CODE_DOWN]          = ADB_KEY_DOWN,
-    [Q_KEY_CODE_LEFT]          = ADB_KEY_LEFT,
-    [Q_KEY_CODE_RIGHT]         = ADB_KEY_RIGHT,
-
-    [Q_KEY_CODE_HELP]          = ADB_KEY_HELP,
-    [Q_KEY_CODE_INSERT]        = ADB_KEY_HELP,
-    [Q_KEY_CODE_DELETE]        = ADB_KEY_FORWARD_DELETE,
-    [Q_KEY_CODE_HOME]          = ADB_KEY_HOME,
-    [Q_KEY_CODE_END]           = ADB_KEY_END,
-    [Q_KEY_CODE_PGUP]          = ADB_KEY_PAGE_UP,
-    [Q_KEY_CODE_PGDN]          = ADB_KEY_PAGE_DOWN,
-
-    [Q_KEY_CODE_POWER]         = ADB_KEY_POWER
+    [0 ... KEY_MAX]  = NO_KEY,
+
+    [KEY_LEFTSHIFT]  = ADB_KEY_LEFT_SHIFT,
+    [KEY_RIGHTSHIFT] = ADB_KEY_RIGHT_SHIFT,
+    [KEY_LEFTALT]    = ADB_KEY_LEFT_OPTION,
+    [KEY_RIGHTALT]   = ADB_KEY_RIGHT_OPTION,
+    [KEY_LEFTCTRL]   = ADB_KEY_LEFT_CONTROL,
+    [KEY_RIGHTCTRL]  = ADB_KEY_RIGHT_CONTROL,
+    [KEY_LEFTMETA]   = ADB_KEY_COMMAND,
+    [KEY_RIGHTMETA]  = ADB_KEY_COMMAND,
+    [KEY_SPACE]      = ADB_KEY_SPACEBAR,
+
+    [KEY_ESC]        = ADB_KEY_ESC,
+    [KEY_1]          = ADB_KEY_1,
+    [KEY_2]          = ADB_KEY_2,
+    [KEY_3]          = ADB_KEY_3,
+    [KEY_4]          = ADB_KEY_4,
+    [KEY_5]          = ADB_KEY_5,
+    [KEY_6]          = ADB_KEY_6,
+    [KEY_7]          = ADB_KEY_7,
+    [KEY_8]          = ADB_KEY_8,
+    [KEY_9]          = ADB_KEY_9,
+    [KEY_0]          = ADB_KEY_0,
+    [KEY_MINUS]      = ADB_KEY_MINUS,
+    [KEY_EQUAL]      = ADB_KEY_EQUAL,
+    [KEY_BACKSPACE]  = ADB_KEY_DELETE,
+    [KEY_TAB]        = ADB_KEY_TAB,
+    [KEY_Q]          = ADB_KEY_Q,
+    [KEY_W]          = ADB_KEY_W,
+    [KEY_E]          = ADB_KEY_E,
+    [KEY_R]          = ADB_KEY_R,
+    [KEY_T]          = ADB_KEY_T,
+    [KEY_Y]          = ADB_KEY_Y,
+    [KEY_U]          = ADB_KEY_U,
+    [KEY_I]          = ADB_KEY_I,
+    [KEY_O]          = ADB_KEY_O,
+    [KEY_P]          = ADB_KEY_P,
+    [KEY_LEFTBRACE]  = ADB_KEY_LEFT_BRACKET,
+    [KEY_RIGHTBRACE] = ADB_KEY_RIGHT_BRACKET,
+    [KEY_ENTER]      = ADB_KEY_RETURN,
+    [KEY_A]          = ADB_KEY_A,
+    [KEY_S]          = ADB_KEY_S,
+    [KEY_D]          = ADB_KEY_D,
+    [KEY_F]          = ADB_KEY_F,
+    [KEY_G]          = ADB_KEY_G,
+    [KEY_H]          = ADB_KEY_H,
+    [KEY_J]          = ADB_KEY_J,
+    [KEY_K]          = ADB_KEY_K,
+    [KEY_L]          = ADB_KEY_L,
+    [KEY_SEMICOLON]  = ADB_KEY_SEMICOLON,
+    [KEY_APOSTROPHE] = ADB_KEY_APOSTROPHE,
+    [KEY_GRAVE]      = ADB_KEY_GRAVE_ACCENT,
+    [KEY_BACKSLASH]  = ADB_KEY_BACKSLASH,
+    [KEY_Z]          = ADB_KEY_Z,
+    [KEY_X]          = ADB_KEY_X,
+    [KEY_C]          = ADB_KEY_C,
+    [KEY_V]          = ADB_KEY_V,
+    [KEY_B]          = ADB_KEY_B,
+    [KEY_N]          = ADB_KEY_N,
+    [KEY_M]          = ADB_KEY_M,
+    [KEY_COMMA]      = ADB_KEY_COMMA,
+    [KEY_DOT]        = ADB_KEY_PERIOD,
+    [KEY_SLASH]      = ADB_KEY_FORWARD_SLASH,
+    [KEY_CAPSLOCK]   = ADB_KEY_CAPS_LOCK,
+
+    [KEY_F1]         = ADB_KEY_F1,
+    [KEY_F2]         = ADB_KEY_F2,
+    [KEY_F3]         = ADB_KEY_F3,
+    [KEY_F4]         = ADB_KEY_F4,
+    [KEY_F5]         = ADB_KEY_F5,
+    [KEY_F6]         = ADB_KEY_F6,
+    [KEY_F7]         = ADB_KEY_F7,
+    [KEY_F8]         = ADB_KEY_F8,
+    [KEY_F9]         = ADB_KEY_F9,
+    [KEY_F10]        = ADB_KEY_F10,
+    [KEY_F11]        = ADB_KEY_F11,
+    [KEY_F12]        = ADB_KEY_F12,
+    [KEY_SYSRQ]      = ADB_KEY_F13,
+    [KEY_SCROLLLOCK] = ADB_KEY_F14,
+    [KEY_PAUSE]      = ADB_KEY_F15,
+
+    [KEY_NUMLOCK]    = ADB_KEY_KP_CLEAR,
+    [KEY_KPEQUAL]    = ADB_KEY_KP_EQUAL,
+    [KEY_KPSLASH]    = ADB_KEY_KP_DIVIDE,
+    [KEY_KPASTERISK] = ADB_KEY_KP_MULTIPLY,
+    [KEY_KPMINUS]    = ADB_KEY_KP_SUBTRACT,
+    [KEY_KPPLUS]     = ADB_KEY_KP_PLUS,
+    [KEY_KPENTER]    = ADB_KEY_KP_ENTER,
+    [KEY_KPDOT]      = ADB_KEY_KP_PERIOD,
+    [KEY_KP0]        = ADB_KEY_KP_0,
+    [KEY_KP1]        = ADB_KEY_KP_1,
+    [KEY_KP2]        = ADB_KEY_KP_2,
+    [KEY_KP3]        = ADB_KEY_KP_3,
+    [KEY_KP4]        = ADB_KEY_KP_4,
+    [KEY_KP5]        = ADB_KEY_KP_5,
+    [KEY_KP6]        = ADB_KEY_KP_6,
+    [KEY_KP7]        = ADB_KEY_KP_7,
+    [KEY_KP8]        = ADB_KEY_KP_8,
+    [KEY_KP9]        = ADB_KEY_KP_9,
+
+    [KEY_UP]         = ADB_KEY_UP,
+    [KEY_DOWN]       = ADB_KEY_DOWN,
+    [KEY_LEFT]       = ADB_KEY_LEFT,
+    [KEY_RIGHT]      = ADB_KEY_RIGHT,
+
+    [KEY_HELP]       = ADB_KEY_HELP,
+    [KEY_INSERT]     = ADB_KEY_HELP,
+    [KEY_DELETE]     = ADB_KEY_FORWARD_DELETE,
+    [KEY_HOME]       = ADB_KEY_HOME,
+    [KEY_END]        = ADB_KEY_END,
+    [KEY_PAGEUP]     = ADB_KEY_PAGE_UP,
+    [KEY_PAGEDOWN]   = ADB_KEY_PAGE_DOWN,
+
+    [KEY_POWER]      = ADB_KEY_POWER
 };
 
 static void adb_kbd_put_keycode(void *opaque, int keycode)
@@ -309,14 +308,13 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     KBDState *s = (KBDState *)dev;
-    int qcode, keycode;
+    int keycode;
 
-    qcode = qemu_input_linux_to_qcode(evt->key.key);
-    if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) {
+    if (evt->key.key >= ARRAY_SIZE(linux_to_adb_keycode)) {
         return;
     }
-    /* FIXME: take handler into account when translating qcode */
-    keycode = qcode_to_adb_keycode[qcode];
+    /* FIXME: take handler into account when translating evt->key.key */
+    keycode = linux_to_adb_keycode[evt->key.key];
     if (keycode == NO_KEY) {  /* We don't want to send this to the guest */
         trace_adb_device_kbd_no_key();
         return;
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 20/38] hw/input/hid: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (18 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 19/38] hw/input/adb-kbd: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 21/38] hw/input/ps2: " marcandre.lureau
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-12-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/input/hid.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/hw/input/hid.c b/hw/input/hid.c
index 013840562f6..467ba8f14f3 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -224,11 +224,10 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     HIDState *hs = (HIDState *)dev;
-    int qcode = qemu_input_linux_to_qcode(evt->key.key);
     int scancodes[3], i, count;
     int slot;
 
-    count = qemu_input_qcode_to_scancode(qcode, evt->key.down,
+    count = qemu_input_linux_to_scancode(evt->key.key, evt->key.down,
                                          scancodes);
     if (hs->n + count > QUEUE_LENGTH) {
         trace_hid_kbd_queue_full();
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 21/38] hw/input/ps2: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (19 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 20/38] hw/input/hid: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 22/38] hw/input/virtio-input: " marcandre.lureau
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-13-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/input/ps2.c        | 51 +++++++++++++++++++++----------------------
 hw/input/trace-events |  2 +-
 2 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 93c3c737205..f2523ff4bc7 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -28,6 +28,7 @@
 #include "hw/core/sysbus.h"
 #include "hw/input/ps2.h"
 #include "migration/vmstate.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "ui/input.h"
 #include "system/reset.h"
@@ -123,20 +124,20 @@ static uint8_t translate_table[256] = {
     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
 };
 
-static unsigned int ps2_modifier_bit(QKeyCode key)
+static unsigned int ps2_modifier_bit(unsigned int key)
 {
     switch (key) {
-    case Q_KEY_CODE_CTRL:
+    case KEY_LEFTCTRL:
         return MOD_CTRL_L;
-    case Q_KEY_CODE_CTRL_R:
+    case KEY_RIGHTCTRL:
         return MOD_CTRL_R;
-    case Q_KEY_CODE_SHIFT:
+    case KEY_LEFTSHIFT:
         return MOD_SHIFT_L;
-    case Q_KEY_CODE_SHIFT_R:
+    case KEY_RIGHTSHIFT:
         return MOD_SHIFT_R;
-    case Q_KEY_CODE_ALT:
+    case KEY_LEFTALT:
         return MOD_ALT_L;
-    case Q_KEY_CODE_ALT_R:
+    case KEY_RIGHTALT:
         return MOD_ALT_R;
     default:
         return 0;
@@ -313,7 +314,6 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                                QemuInputEvent *evt)
 {
     PS2KbdState *s = (PS2KbdState *)dev;
-    int qcode;
     uint16_t keycode = 0;
     int mod;
 
@@ -324,10 +324,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
 
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    qcode = qemu_input_linux_to_qcode(evt->key.key);
 
-    mod = ps2_modifier_bit(qcode);
-    trace_ps2_keyboard_event(s, qcode, evt->key.down, mod,
+    mod = ps2_modifier_bit(evt->key.key);
+    trace_ps2_keyboard_event(s, evt->key.key, evt->key.down, mod,
                              s->modifiers, s->scancode_set, s->translate);
     if (evt->key.down) {
         s->modifiers |= mod;
@@ -336,7 +335,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
     }
 
     if (s->scancode_set == 1) {
-        if (qcode == Q_KEY_CODE_PAUSE) {
+        if (evt->key.key == KEY_PAUSE) {
             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
                 if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
@@ -354,7 +353,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0xc5);
                 }
             }
-        } else if (qcode == Q_KEY_CODE_PRINT) {
+        } else if (evt->key.key == KEY_SYSRQ) {
             if (s->modifiers & MOD_ALT_L) {
                 if (evt->key.down) {
                     ps2_put_keycode(s, 0xb8);
@@ -401,12 +400,12 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0xaa);
                 }
             }
-        } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2)
+        } else if ((evt->key.key == KEY_HANGEUL || evt->key.key == KEY_HANJA)
                    && !evt->key.down) {
             /* Ignore release for these keys */
         } else {
-            if (qcode < qemu_input_map_qcode_to_atset1_len) {
-                keycode = qemu_input_map_qcode_to_atset1[qcode];
+            if (evt->key.key < qemu_input_map_linux_to_atset1_len) {
+                keycode = qemu_input_map_linux_to_atset1[evt->key.key];
             }
             if (keycode) {
                 if (keycode & 0xff00) {
@@ -418,11 +417,11 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 ps2_put_keycode(s, keycode & 0xff);
             } else {
                 qemu_log_mask(LOG_UNIMP,
-                              "ps2: ignoring key with qcode %d\n", qcode);
+                              "ps2: ignoring key %u\n", evt->key.key);
             }
         }
     } else if (s->scancode_set == 2) {
-        if (qcode == Q_KEY_CODE_PAUSE) {
+        if (evt->key.key == KEY_PAUSE) {
             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
                 if (evt->key.down) {
                     ps2_put_keycode(s, 0xe0);
@@ -443,7 +442,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0x77);
                 }
             }
-        } else if (qcode == Q_KEY_CODE_PRINT) {
+        } else if (evt->key.key == KEY_SYSRQ) {
             if (s->modifiers & MOD_ALT_L) {
                 if (evt->key.down) {
                     ps2_put_keycode(s, 0xf0);
@@ -499,12 +498,12 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                     ps2_put_keycode(s, 0x12);
                 }
             }
-        } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2) &&
+        } else if ((evt->key.key == KEY_HANGEUL || evt->key.key == KEY_HANJA) &&
                    !evt->key.down) {
             /* Ignore release for these keys */
         } else {
-            if (qcode < qemu_input_map_qcode_to_atset2_len) {
-                keycode = qemu_input_map_qcode_to_atset2[qcode];
+            if (evt->key.key < qemu_input_map_linux_to_atset2_len) {
+                keycode = qemu_input_map_linux_to_atset2[evt->key.key];
             }
             if (keycode) {
                 if (keycode & 0xff00) {
@@ -516,12 +515,12 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                 ps2_put_keycode(s, keycode & 0xff);
             } else {
                 qemu_log_mask(LOG_UNIMP,
-                              "ps2: ignoring key with qcode %d\n", qcode);
+                              "ps2: ignoring key %u\n", evt->key.key);
             }
         }
     } else if (s->scancode_set == 3) {
-        if (qcode < qemu_input_map_qcode_to_atset3_len) {
-            keycode = qemu_input_map_qcode_to_atset3[qcode];
+        if (evt->key.key < qemu_input_map_linux_to_atset3_len) {
+            keycode = qemu_input_map_linux_to_atset3[evt->key.key];
         }
         if (keycode) {
             /* FIXME: break code should be configured on a key by key basis */
@@ -531,7 +530,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
             ps2_put_keycode(s, keycode);
         } else {
             qemu_log_mask(LOG_UNIMP,
-                          "ps2: ignoring key with qcode %d\n", qcode);
+                          "ps2: ignoring key %u\n", evt->key.key);
         }
     }
 }
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 1484625565b..43900914be2 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -30,7 +30,7 @@ pckbd_kbd_write_data(uint64_t val) "0x%02"PRIx64
 
 # ps2.c
 ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x"
-ps2_keyboard_event(void *opaque, int qcode, int down, unsigned int modifier, unsigned int modifiers, int set, int xlate) "%p qcode %d down %d modifier 0x%x modifiers 0x%x set %d xlate %d"
+ps2_keyboard_event(void *opaque, unsigned int lnx, int down, unsigned int modifier, unsigned int modifiers, int set, int xlate) "%p lnx %u down %d modifier 0x%x modifiers 0x%x set %d xlate %d"
 ps2_read_data(void *opaque) "%p"
 ps2_set_ledstate(void *s, int ledstate) "%p ledstate %d"
 ps2_reset_keyboard(void *s) "%p"
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 22/38] hw/input/virtio-input: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (20 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 21/38] hw/input/ps2: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 23/38] hw/m68k/next-kbd: " marcandre.lureau
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Gerd Hoffmann, Michael S. Tsirkin

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-14-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/input/virtio-input-hid.c | 40 +++++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 1d2e922567a..75fe45d89a2 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -83,23 +83,13 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
 {
     VirtIOInput *vinput = VIRTIO_INPUT(dev);
     virtio_input_event event;
-    int qcode;
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        qcode = qemu_input_linux_to_qcode(evt->key.key);
-        if (qcode < qemu_input_map_qcode_to_linux_len &&
-            qemu_input_map_qcode_to_linux[qcode]) {
-            event.type  = cpu_to_le16(EV_KEY);
-            event.code  = cpu_to_le16(qemu_input_map_qcode_to_linux[qcode]);
-            event.value = cpu_to_le32(evt->key.down ? 1 : 0);
-            virtio_input_send(vinput, &event);
-        } else {
-            if (evt->key.down) {
-                fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
-                        qcode, QKeyCode_str(qcode));
-            }
-        }
+        event.type  = cpu_to_le16(EV_KEY);
+        event.code  = cpu_to_le16(evt->key.key);
+        event.value = cpu_to_le32(evt->key.down ? 1 : 0);
+        virtio_input_send(vinput, &event);
         break;
     case INPUT_EVENT_KIND_BTN:
         if ((evt->btn.button == INPUT_BUTTON_WHEEL_UP ||
@@ -293,12 +283,28 @@ static void virtio_keyboard_init(Object *obj)
 {
     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
     VirtIOInput *vinput = VIRTIO_INPUT(obj);
+    virtio_input_config ext = {
+        .select = VIRTIO_INPUT_CFG_EV_BITS,
+        .subsel = EV_KEY,
+        .size = DIV_ROUND_UP(KEY_REPLY, 8)
+    };
+    unsigned int i;
 
     vhid->handler = &virtio_keyboard_handler;
     virtio_input_init_config(vinput, virtio_keyboard_config);
-    virtio_input_extend_config(vinput, qemu_input_map_qcode_to_linux,
-                               qemu_input_map_qcode_to_linux_len,
-                               VIRTIO_INPUT_CFG_EV_BITS, EV_KEY);
+
+    /*
+     * Cover as many keys as possible since we cannot tell what keys the host
+     * supports. This follows Linux xen-kbdfront's approach:
+     * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/diff/drivers/input/xen-kbdfront.c?id=4ee36dc08e5c4d16d078f59acd6d9d536f9718dd
+     *
+     * Stop before KEY_REPLY for migration compatibility.
+     */
+    for (i = KEY_ESC; i < KEY_REPLY; i++) {
+        ext.u.bitmap[i / 8] |= (1 << (i % 8));
+    }
+
+    virtio_input_add_config(vinput, &ext);
 }
 
 static const TypeInfo virtio_keyboard_info = {
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 23/38] hw/m68k/next-kbd: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (21 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 22/38] hw/input/virtio-input: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 24/38] replay: " marcandre.lureau
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Thomas Huth

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-15-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 hw/m68k/next-kbd.c | 118 ++++++++++++++++++++++-----------------------
 1 file changed, 59 insertions(+), 59 deletions(-)

diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 7efbd806b7c..7be5ab2fb79 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -31,6 +31,7 @@
 #include "qemu/log.h"
 #include "hw/core/sysbus.h"
 #include "hw/m68k/next-cube.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "migration/vmstate.h"
 #include "qom/object.h"
@@ -165,59 +166,59 @@ static const MemoryRegionOps kbd_ops = {
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static const int qcode_to_nextkbd_keycode[] = {
-    [Q_KEY_CODE_ESC]           = 0x49,
-    [Q_KEY_CODE_1]             = 0x4a,
-    [Q_KEY_CODE_2]             = 0x4b,
-    [Q_KEY_CODE_3]             = 0x4c,
-    [Q_KEY_CODE_4]             = 0x4d,
-    [Q_KEY_CODE_5]             = 0x50,
-    [Q_KEY_CODE_6]             = 0x4f,
-    [Q_KEY_CODE_7]             = 0x4e,
-    [Q_KEY_CODE_8]             = 0x1e,
-    [Q_KEY_CODE_9]             = 0x1f,
-    [Q_KEY_CODE_0]             = 0x20,
-    [Q_KEY_CODE_MINUS]         = 0x1d,
-    [Q_KEY_CODE_EQUAL]         = 0x1c,
-    [Q_KEY_CODE_BACKSPACE]     = 0x1b,
-
-    [Q_KEY_CODE_Q]             = 0x42,
-    [Q_KEY_CODE_W]             = 0x43,
-    [Q_KEY_CODE_E]             = 0x44,
-    [Q_KEY_CODE_R]             = 0x45,
-    [Q_KEY_CODE_T]             = 0x48,
-    [Q_KEY_CODE_Y]             = 0x47,
-    [Q_KEY_CODE_U]             = 0x46,
-    [Q_KEY_CODE_I]             = 0x06,
-    [Q_KEY_CODE_O]             = 0x07,
-    [Q_KEY_CODE_P]             = 0x08,
-    [Q_KEY_CODE_RET]           = 0x2a,
-    [Q_KEY_CODE_A]             = 0x39,
-    [Q_KEY_CODE_S]             = 0x3a,
-
-    [Q_KEY_CODE_D]             = 0x3b,
-    [Q_KEY_CODE_F]             = 0x3c,
-    [Q_KEY_CODE_G]             = 0x3d,
-    [Q_KEY_CODE_H]             = 0x40,
-    [Q_KEY_CODE_J]             = 0x3f,
-    [Q_KEY_CODE_K]             = 0x3e,
-    [Q_KEY_CODE_L]             = 0x2d,
-    [Q_KEY_CODE_SEMICOLON]     = 0x2c,
-    [Q_KEY_CODE_APOSTROPHE]    = 0x2b,
-    [Q_KEY_CODE_GRAVE_ACCENT]  = 0x26,
-    [Q_KEY_CODE_Z]             = 0x31,
-    [Q_KEY_CODE_X]             = 0x32,
-    [Q_KEY_CODE_C]             = 0x33,
-    [Q_KEY_CODE_V]             = 0x34,
-
-    [Q_KEY_CODE_B]             = 0x35,
-    [Q_KEY_CODE_N]             = 0x37,
-    [Q_KEY_CODE_M]             = 0x36,
-    [Q_KEY_CODE_COMMA]         = 0x2e,
-    [Q_KEY_CODE_DOT]           = 0x2f,
-    [Q_KEY_CODE_SLASH]         = 0x30,
-
-    [Q_KEY_CODE_SPC]           = 0x38,
+static const int linux_to_nextkbd_keycode[] = {
+    [KEY_ESC]        = 0x49,
+    [KEY_1]          = 0x4a,
+    [KEY_2]          = 0x4b,
+    [KEY_3]          = 0x4c,
+    [KEY_4]          = 0x4d,
+    [KEY_5]          = 0x50,
+    [KEY_6]          = 0x4f,
+    [KEY_7]          = 0x4e,
+    [KEY_8]          = 0x1e,
+    [KEY_9]          = 0x1f,
+    [KEY_0]          = 0x20,
+    [KEY_MINUS]      = 0x1d,
+    [KEY_EQUAL]      = 0x1c,
+    [KEY_BACKSPACE]  = 0x1b,
+
+    [KEY_Q]          = 0x42,
+    [KEY_W]          = 0x43,
+    [KEY_E]          = 0x44,
+    [KEY_R]          = 0x45,
+    [KEY_T]          = 0x48,
+    [KEY_Y]          = 0x47,
+    [KEY_U]          = 0x46,
+    [KEY_I]          = 0x06,
+    [KEY_O]          = 0x07,
+    [KEY_P]          = 0x08,
+    [KEY_ENTER]      = 0x2a,
+    [KEY_A]          = 0x39,
+    [KEY_S]          = 0x3a,
+
+    [KEY_D]          = 0x3b,
+    [KEY_F]          = 0x3c,
+    [KEY_G]          = 0x3d,
+    [KEY_H]          = 0x40,
+    [KEY_J]          = 0x3f,
+    [KEY_K]          = 0x3e,
+    [KEY_L]          = 0x2d,
+    [KEY_SEMICOLON]  = 0x2c,
+    [KEY_APOSTROPHE] = 0x2b,
+    [KEY_GRAVE]      = 0x26,
+    [KEY_Z]          = 0x31,
+    [KEY_X]          = 0x32,
+    [KEY_C]          = 0x33,
+    [KEY_V]          = 0x34,
+
+    [KEY_B]          = 0x35,
+    [KEY_N]          = 0x37,
+    [KEY_M]          = 0x36,
+    [KEY_COMMA]      = 0x2e,
+    [KEY_DOT]        = 0x2f,
+    [KEY_SLASH]      = 0x30,
+
+    [KEY_SPACE]      = 0x38,
 };
 
 static void nextkbd_put_keycode(NextKBDState *s, int keycode)
@@ -246,15 +247,14 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
                           QemuInputEvent *evt)
 {
     NextKBDState *s = NEXTKBD(dev);
-    int qcode, keycode;
+    int keycode;
 
-    qcode = qemu_input_linux_to_qcode(evt->key.key);
-    if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) {
+    if (evt->key.key >= ARRAY_SIZE(linux_to_nextkbd_keycode)) {
         return;
     }
 
     /* Shift key currently has no keycode, so handle separately */
-    if (qcode == Q_KEY_CODE_SHIFT) {
+    if (evt->key.key == KEY_LEFTSHIFT) {
         if (evt->key.down) {
             s->shift |= KD_LSHIFT;
         } else {
@@ -262,7 +262,7 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
         }
     }
 
-    if (qcode == Q_KEY_CODE_SHIFT_R) {
+    if (evt->key.key == KEY_RIGHTSHIFT) {
         if (evt->key.down) {
             s->shift |= KD_RSHIFT;
         } else {
@@ -270,7 +270,7 @@ static void nextkbd_event(DeviceState *dev, QemuConsole *src,
         }
     }
 
-    keycode = qcode_to_nextkbd_keycode[qcode];
+    keycode = linux_to_nextkbd_keycode[evt->key.key];
     if (!keycode) {
         return;
     }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 24/38] replay: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (22 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 23/38] hw/m68k/next-kbd: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 25/38] ui/cocoa: " marcandre.lureau
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Marc-André Lureau, Paolo Bonzini,
	Alex Bennée, John Snow, Cleber Rosa

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-16-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
[ Marc-André - update replay-dump.py ]
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 replay/replay-input.c  | 20 +++-----------------
 replay/replay.c        |  2 +-
 scripts/replay-dump.py |  8 +++++++-
 3 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/replay/replay-input.c b/replay/replay-input.c
index acf0993c728..c86e00af0ef 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -23,8 +23,7 @@ void replay_save_input_event(QemuInputEvent *evt)
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        replay_put_dword(KEY_VALUE_KIND_QCODE);
-        replay_put_dword(qemu_input_linux_to_qcode(evt->key.key));
+        replay_put_dword(evt->key.key);
         replay_put_byte(evt->key.down);
         break;
     case INPUT_EVENT_KIND_BTN:
@@ -55,25 +54,12 @@ void replay_save_input_event(QemuInputEvent *evt)
 QemuInputEvent *replay_read_input_event(void)
 {
     QemuInputEvent *evt = g_new(QemuInputEvent, 1);
-    int qcode;
 
     evt->type = replay_get_dword();
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        switch (replay_get_dword()) {
-        case KEY_VALUE_KIND_NUMBER:
-            qcode = qemu_input_key_number_to_qcode(replay_get_qword());
-            evt->key.down = replay_get_byte();
-            break;
-        case KEY_VALUE_KIND_QCODE:
-            qcode = (QKeyCode)replay_get_dword();
-            evt->key.down = replay_get_byte();
-            break;
-        default:
-            g_assert_not_reached();
-        }
-        evt->key.key = qcode < qemu_input_map_qcode_to_linux_len ?
-                       qemu_input_map_qcode_to_linux[qcode] : 0;
+        evt->key.key = replay_get_dword();
+        evt->key.down = replay_get_byte();
         break;
     case INPUT_EVENT_KIND_BTN:
         evt->btn.button = (InputButton)replay_get_dword();
diff --git a/replay/replay.c b/replay/replay.c
index 2e5c6fa82ea..14437b32566 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -22,7 +22,7 @@
 
 /* Current version of the replay mechanism.
    Increase it when file format changes. */
-#define REPLAY_VERSION              0xe0200d
+#define REPLAY_VERSION              0xe0200e
 /* Size of replay log header */
 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 
diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py
index 081aaa36c5e..ce1031b4ad4 100755
--- a/scripts/replay-dump.py
+++ b/scripts/replay-dump.py
@@ -398,6 +398,9 @@ def decode_end(eid, name, dumpfile):
 # EVENT_AUDIO_IN has changed
 v13_event_table = v12_event_table
 
+# EVENT_ASYNC_INPUT has changed
+v14_event_table = v13_event_table
+
 def parse_arguments():
     "Grab arguments for script"
     parser = argparse.ArgumentParser()
@@ -416,7 +419,10 @@ def decode_file(filename):
     # see REPLAY_VERSION
     print("HEADER: version 0x%x" % (version))
 
-    if version == 0xe0200d:
+    if version == 0xe0200e:
+        event_decode_table = v14_event_table
+        replay_state.checkpoint_start = 30
+    elif version == 0xe0200d:
         event_decode_table = v13_event_table
         replay_state.checkpoint_start = 30
     elif version == 0xe0200c:
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 25/38] ui/cocoa: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (23 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 24/38] replay: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 26/38] ui/dbus: " marcandre.lureau
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Akihiko Odaki, Peter Maydell,
	Philippe Mathieu-Daudé, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-17-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/cocoa.m | 328 ++++++++++++++++++++++++-----------------------------
 1 file changed, 148 insertions(+), 180 deletions(-)

diff --git a/ui/cocoa.m b/ui/cocoa.m
index ee53e7c72ed..c5e639ab98d 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -30,6 +30,7 @@
 
 #include "qemu/help-texts.h"
 #include "qemu-main.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/clipboard.h"
 #include "ui/console.h"
 #include "ui/input.h"
@@ -140,124 +141,124 @@ static bool bool_with_bql(BoolCodeBlock block)
     return val;
 }
 
-// Mac to QKeyCode conversion
-static const int mac_to_qkeycode_map[] = {
-    [kVK_ANSI_A] = Q_KEY_CODE_A,
-    [kVK_ANSI_B] = Q_KEY_CODE_B,
-    [kVK_ANSI_C] = Q_KEY_CODE_C,
-    [kVK_ANSI_D] = Q_KEY_CODE_D,
-    [kVK_ANSI_E] = Q_KEY_CODE_E,
-    [kVK_ANSI_F] = Q_KEY_CODE_F,
-    [kVK_ANSI_G] = Q_KEY_CODE_G,
-    [kVK_ANSI_H] = Q_KEY_CODE_H,
-    [kVK_ANSI_I] = Q_KEY_CODE_I,
-    [kVK_ANSI_J] = Q_KEY_CODE_J,
-    [kVK_ANSI_K] = Q_KEY_CODE_K,
-    [kVK_ANSI_L] = Q_KEY_CODE_L,
-    [kVK_ANSI_M] = Q_KEY_CODE_M,
-    [kVK_ANSI_N] = Q_KEY_CODE_N,
-    [kVK_ANSI_O] = Q_KEY_CODE_O,
-    [kVK_ANSI_P] = Q_KEY_CODE_P,
-    [kVK_ANSI_Q] = Q_KEY_CODE_Q,
-    [kVK_ANSI_R] = Q_KEY_CODE_R,
-    [kVK_ANSI_S] = Q_KEY_CODE_S,
-    [kVK_ANSI_T] = Q_KEY_CODE_T,
-    [kVK_ANSI_U] = Q_KEY_CODE_U,
-    [kVK_ANSI_V] = Q_KEY_CODE_V,
-    [kVK_ANSI_W] = Q_KEY_CODE_W,
-    [kVK_ANSI_X] = Q_KEY_CODE_X,
-    [kVK_ANSI_Y] = Q_KEY_CODE_Y,
-    [kVK_ANSI_Z] = Q_KEY_CODE_Z,
-
-    [kVK_ANSI_0] = Q_KEY_CODE_0,
-    [kVK_ANSI_1] = Q_KEY_CODE_1,
-    [kVK_ANSI_2] = Q_KEY_CODE_2,
-    [kVK_ANSI_3] = Q_KEY_CODE_3,
-    [kVK_ANSI_4] = Q_KEY_CODE_4,
-    [kVK_ANSI_5] = Q_KEY_CODE_5,
-    [kVK_ANSI_6] = Q_KEY_CODE_6,
-    [kVK_ANSI_7] = Q_KEY_CODE_7,
-    [kVK_ANSI_8] = Q_KEY_CODE_8,
-    [kVK_ANSI_9] = Q_KEY_CODE_9,
-
-    [kVK_ANSI_Grave] = Q_KEY_CODE_GRAVE_ACCENT,
-    [kVK_ANSI_Minus] = Q_KEY_CODE_MINUS,
-    [kVK_ANSI_Equal] = Q_KEY_CODE_EQUAL,
-    [kVK_Delete] = Q_KEY_CODE_BACKSPACE,
-    [kVK_CapsLock] = Q_KEY_CODE_CAPS_LOCK,
-    [kVK_Tab] = Q_KEY_CODE_TAB,
-    [kVK_Return] = Q_KEY_CODE_RET,
-    [kVK_ANSI_LeftBracket] = Q_KEY_CODE_BRACKET_LEFT,
-    [kVK_ANSI_RightBracket] = Q_KEY_CODE_BRACKET_RIGHT,
-    [kVK_ANSI_Backslash] = Q_KEY_CODE_BACKSLASH,
-    [kVK_ANSI_Semicolon] = Q_KEY_CODE_SEMICOLON,
-    [kVK_ANSI_Quote] = Q_KEY_CODE_APOSTROPHE,
-    [kVK_ANSI_Comma] = Q_KEY_CODE_COMMA,
-    [kVK_ANSI_Period] = Q_KEY_CODE_DOT,
-    [kVK_ANSI_Slash] = Q_KEY_CODE_SLASH,
-    [kVK_Space] = Q_KEY_CODE_SPC,
-
-    [kVK_ANSI_Keypad0] = Q_KEY_CODE_KP_0,
-    [kVK_ANSI_Keypad1] = Q_KEY_CODE_KP_1,
-    [kVK_ANSI_Keypad2] = Q_KEY_CODE_KP_2,
-    [kVK_ANSI_Keypad3] = Q_KEY_CODE_KP_3,
-    [kVK_ANSI_Keypad4] = Q_KEY_CODE_KP_4,
-    [kVK_ANSI_Keypad5] = Q_KEY_CODE_KP_5,
-    [kVK_ANSI_Keypad6] = Q_KEY_CODE_KP_6,
-    [kVK_ANSI_Keypad7] = Q_KEY_CODE_KP_7,
-    [kVK_ANSI_Keypad8] = Q_KEY_CODE_KP_8,
-    [kVK_ANSI_Keypad9] = Q_KEY_CODE_KP_9,
-    [kVK_ANSI_KeypadDecimal] = Q_KEY_CODE_KP_DECIMAL,
-    [kVK_ANSI_KeypadEnter] = Q_KEY_CODE_KP_ENTER,
-    [kVK_ANSI_KeypadPlus] = Q_KEY_CODE_KP_ADD,
-    [kVK_ANSI_KeypadMinus] = Q_KEY_CODE_KP_SUBTRACT,
-    [kVK_ANSI_KeypadMultiply] = Q_KEY_CODE_KP_MULTIPLY,
-    [kVK_ANSI_KeypadDivide] = Q_KEY_CODE_KP_DIVIDE,
-    [kVK_ANSI_KeypadEquals] = Q_KEY_CODE_KP_EQUALS,
-    [kVK_ANSI_KeypadClear] = Q_KEY_CODE_NUM_LOCK,
-
-    [kVK_UpArrow] = Q_KEY_CODE_UP,
-    [kVK_DownArrow] = Q_KEY_CODE_DOWN,
-    [kVK_LeftArrow] = Q_KEY_CODE_LEFT,
-    [kVK_RightArrow] = Q_KEY_CODE_RIGHT,
-
-    [kVK_Help] = Q_KEY_CODE_INSERT,
-    [kVK_Home] = Q_KEY_CODE_HOME,
-    [kVK_PageUp] = Q_KEY_CODE_PGUP,
-    [kVK_PageDown] = Q_KEY_CODE_PGDN,
-    [kVK_End] = Q_KEY_CODE_END,
-    [kVK_ForwardDelete] = Q_KEY_CODE_DELETE,
-
-    [kVK_Escape] = Q_KEY_CODE_ESC,
+// Mac to Linux conversion
+static const unsigned int mac_to_linux_map[] = {
+    [kVK_ANSI_A] = KEY_A,
+    [kVK_ANSI_B] = KEY_B,
+    [kVK_ANSI_C] = KEY_C,
+    [kVK_ANSI_D] = KEY_D,
+    [kVK_ANSI_E] = KEY_E,
+    [kVK_ANSI_F] = KEY_F,
+    [kVK_ANSI_G] = KEY_G,
+    [kVK_ANSI_H] = KEY_H,
+    [kVK_ANSI_I] = KEY_I,
+    [kVK_ANSI_J] = KEY_J,
+    [kVK_ANSI_K] = KEY_K,
+    [kVK_ANSI_L] = KEY_L,
+    [kVK_ANSI_M] = KEY_M,
+    [kVK_ANSI_N] = KEY_N,
+    [kVK_ANSI_O] = KEY_O,
+    [kVK_ANSI_P] = KEY_P,
+    [kVK_ANSI_Q] = KEY_Q,
+    [kVK_ANSI_R] = KEY_R,
+    [kVK_ANSI_S] = KEY_S,
+    [kVK_ANSI_T] = KEY_T,
+    [kVK_ANSI_U] = KEY_U,
+    [kVK_ANSI_V] = KEY_V,
+    [kVK_ANSI_W] = KEY_W,
+    [kVK_ANSI_X] = KEY_X,
+    [kVK_ANSI_Y] = KEY_Y,
+    [kVK_ANSI_Z] = KEY_Z,
+
+    [kVK_ANSI_0] = KEY_0,
+    [kVK_ANSI_1] = KEY_1,
+    [kVK_ANSI_2] = KEY_2,
+    [kVK_ANSI_3] = KEY_3,
+    [kVK_ANSI_4] = KEY_4,
+    [kVK_ANSI_5] = KEY_5,
+    [kVK_ANSI_6] = KEY_6,
+    [kVK_ANSI_7] = KEY_7,
+    [kVK_ANSI_8] = KEY_8,
+    [kVK_ANSI_9] = KEY_9,
+
+    [kVK_ANSI_Grave] = KEY_GRAVE,
+    [kVK_ANSI_Minus] = KEY_MINUS,
+    [kVK_ANSI_Equal] = KEY_EQUAL,
+    [kVK_Delete] = KEY_BACKSPACE,
+    [kVK_CapsLock] = KEY_CAPSLOCK,
+    [kVK_Tab] = KEY_TAB,
+    [kVK_Return] = KEY_ENTER,
+    [kVK_ANSI_LeftBracket] = KEY_LEFTBRACE,
+    [kVK_ANSI_RightBracket] = KEY_RIGHTBRACE,
+    [kVK_ANSI_Backslash] = KEY_BACKSLASH,
+    [kVK_ANSI_Semicolon] = KEY_SEMICOLON,
+    [kVK_ANSI_Quote] = KEY_APOSTROPHE,
+    [kVK_ANSI_Comma] = KEY_COMMA,
+    [kVK_ANSI_Period] = KEY_DOT,
+    [kVK_ANSI_Slash] = KEY_SLASH,
+    [kVK_Space] = KEY_SPACE,
+
+    [kVK_ANSI_Keypad0] = KEY_KP0,
+    [kVK_ANSI_Keypad1] = KEY_KP1,
+    [kVK_ANSI_Keypad2] = KEY_KP2,
+    [kVK_ANSI_Keypad3] = KEY_KP3,
+    [kVK_ANSI_Keypad4] = KEY_KP4,
+    [kVK_ANSI_Keypad5] = KEY_KP5,
+    [kVK_ANSI_Keypad6] = KEY_KP6,
+    [kVK_ANSI_Keypad7] = KEY_KP7,
+    [kVK_ANSI_Keypad8] = KEY_KP8,
+    [kVK_ANSI_Keypad9] = KEY_KP9,
+    [kVK_ANSI_KeypadDecimal] = KEY_KPDOT,
+    [kVK_ANSI_KeypadEnter] = KEY_KPENTER,
+    [kVK_ANSI_KeypadPlus] = KEY_KPPLUS,
+    [kVK_ANSI_KeypadMinus] = KEY_KPMINUS,
+    [kVK_ANSI_KeypadMultiply] = KEY_KPASTERISK,
+    [kVK_ANSI_KeypadDivide] = KEY_KPSLASH,
+    [kVK_ANSI_KeypadEquals] = KEY_KPEQUAL,
+    [kVK_ANSI_KeypadClear] = KEY_NUMLOCK,
+
+    [kVK_UpArrow] = KEY_UP,
+    [kVK_DownArrow] = KEY_DOWN,
+    [kVK_LeftArrow] = KEY_LEFT,
+    [kVK_RightArrow] = KEY_RIGHT,
+
+    [kVK_Help] = KEY_INSERT,
+    [kVK_Home] = KEY_HOME,
+    [kVK_PageUp] = KEY_PAGEUP,
+    [kVK_PageDown] = KEY_PAGEDOWN,
+    [kVK_End] = KEY_END,
+    [kVK_ForwardDelete] = KEY_DELETE,
+
+    [kVK_Escape] = KEY_ESC,
 
     /* The Power key can't be used directly because the operating system uses
      * it. This key can be emulated by using it in place of another key such as
      * F1. Don't forget to disable the real key binding.
      */
-    /* [kVK_F1] = Q_KEY_CODE_POWER, */
-
-    [kVK_F1] = Q_KEY_CODE_F1,
-    [kVK_F2] = Q_KEY_CODE_F2,
-    [kVK_F3] = Q_KEY_CODE_F3,
-    [kVK_F4] = Q_KEY_CODE_F4,
-    [kVK_F5] = Q_KEY_CODE_F5,
-    [kVK_F6] = Q_KEY_CODE_F6,
-    [kVK_F7] = Q_KEY_CODE_F7,
-    [kVK_F8] = Q_KEY_CODE_F8,
-    [kVK_F9] = Q_KEY_CODE_F9,
-    [kVK_F10] = Q_KEY_CODE_F10,
-    [kVK_F11] = Q_KEY_CODE_F11,
-    [kVK_F12] = Q_KEY_CODE_F12,
-    [kVK_F13] = Q_KEY_CODE_PRINT,
-    [kVK_F14] = Q_KEY_CODE_SCROLL_LOCK,
-    [kVK_F15] = Q_KEY_CODE_PAUSE,
+    /* [kVK_F1] = KEY_POWER, */
+
+    [kVK_F1] = KEY_F1,
+    [kVK_F2] = KEY_F2,
+    [kVK_F3] = KEY_F3,
+    [kVK_F4] = KEY_F4,
+    [kVK_F5] = KEY_F5,
+    [kVK_F6] = KEY_F6,
+    [kVK_F7] = KEY_F7,
+    [kVK_F8] = KEY_F8,
+    [kVK_F9] = KEY_F9,
+    [kVK_F10] = KEY_F10,
+    [kVK_F11] = KEY_F11,
+    [kVK_F12] = KEY_F12,
+    [kVK_F13] = KEY_SYSRQ,
+    [kVK_F14] = KEY_SCROLLLOCK,
+    [kVK_F15] = KEY_PAUSE,
 
     // JIS keyboards only
-    [kVK_JIS_Yen] = Q_KEY_CODE_YEN,
-    [kVK_JIS_Underscore] = Q_KEY_CODE_RO,
-    [kVK_JIS_KeypadComma] = Q_KEY_CODE_KP_COMMA,
-    [kVK_JIS_Eisu] = Q_KEY_CODE_MUHENKAN,
-    [kVK_JIS_Kana] = Q_KEY_CODE_HENKAN,
+    [kVK_JIS_Yen] = KEY_YEN,
+    [kVK_JIS_Underscore] = KEY_RO,
+    [kVK_JIS_KeypadComma] = KEY_KPCOMMA,
+    [kVK_JIS_Eisu] = KEY_MUHENKAN,
+    [kVK_JIS_Kana] = KEY_HENKAN,
 
     /*
      * The eject and volume keys can't be used here because they are handled at
@@ -265,13 +266,13 @@ static bool bool_with_bql(BoolCodeBlock block)
      */
 };
 
-static int cocoa_keycode_to_qemu(int keycode)
+static unsigned int cocoa_keycode_to_linux(int keycode)
 {
-    if (ARRAY_SIZE(mac_to_qkeycode_map) <= keycode) {
+    if (ARRAY_SIZE(mac_to_linux_map) <= keycode) {
         error_report("(cocoa) warning unknown keycode 0x%x", keycode);
         return 0;
     }
-    return mac_to_qkeycode_map[keycode];
+    return mac_to_linux_map[keycode];
 }
 
 /* Displays an alert dialog box with the specified message */
@@ -766,9 +767,8 @@ - (void) setFullGrab:(id)sender
     CFRelease(tapEventsSrc);
 }
 
-- (void) toggleKey: (int)keycode {
-    unsigned int lnx = qemu_input_map_qcode_to_linux[keycode];
-    qkbd_state_key_event(kbd, lnx, !qkbd_state_key_get(kbd, lnx));
+- (void) toggleKey: (unsigned int)keycode {
+    qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode));
 }
 
 // Does the work of sending input to the monitor
@@ -848,7 +848,7 @@ - (bool) handleEventLocked:(NSEvent *)event
     /* Return true if we handled the event, false if it should be given to OSX */
     COCOA_DEBUG("QemuCocoaView: handleEvent\n");
     InputButton button;
-    int keycode = 0;
+    unsigned int keycode;
     NSUInteger modifiers = [event modifierFlags];
 
     /*
@@ -890,62 +890,34 @@ - (bool) handleEventLocked:(NSEvent *)event
      */
     if (!!(modifiers & NSEventModifierFlagCapsLock) !=
         qkbd_state_modifier_get(kbd, QKBD_MOD_CAPSLOCK)) {
-        qkbd_state_key_event(kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CAPS_LOCK],
-                             true);
-        qkbd_state_key_event(kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CAPS_LOCK],
-                             false);
+        qkbd_state_key_event(kbd, KEY_CAPSLOCK, true);
+        qkbd_state_key_event(kbd, KEY_CAPSLOCK, false);
     }
 
     if (!(modifiers & NSEventModifierFlagShift)) {
-        qkbd_state_key_event(kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_SHIFT],
-                             false);
-        qkbd_state_key_event(kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_SHIFT_R],
-                             false);
+        qkbd_state_key_event(kbd, KEY_LEFTSHIFT, false);
+        qkbd_state_key_event(kbd, KEY_RIGHTSHIFT, false);
     }
     if (!(modifiers & NSEventModifierFlagControl)) {
-        qkbd_state_key_event(kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CTRL],
-                             false);
-        qkbd_state_key_event(kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_CTRL_R],
-                             false);
+        qkbd_state_key_event(kbd, KEY_LEFTCTRL, false);
+        qkbd_state_key_event(kbd, KEY_RIGHTCTRL, false);
     }
     if (!(modifiers & NSEventModifierFlagOption)) {
         if (swap_opt_cmd) {
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_L],
-                                 false);
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_R],
-                                 false);
+            qkbd_state_key_event(kbd, KEY_LEFTMETA, false);
+            qkbd_state_key_event(kbd, KEY_RIGHTMETA, false);
         } else {
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT],
-                                 false);
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT_R],
-                                 false);
+            qkbd_state_key_event(kbd, KEY_LEFTALT, false);
+            qkbd_state_key_event(kbd, KEY_RIGHTALT, false);
         }
     }
     if (!(modifiers & NSEventModifierFlagCommand)) {
         if (swap_opt_cmd) {
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT],
-                                 false);
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_ALT_R],
-                                 false);
+            qkbd_state_key_event(kbd, KEY_LEFTALT, false);
+            qkbd_state_key_event(kbd, KEY_RIGHTALT, false);
         } else {
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_L],
-                                 false);
-            qkbd_state_key_event(kbd,
-                                 qemu_input_map_qcode_to_linux[Q_KEY_CODE_META_R],
-                                 false);
+            qkbd_state_key_event(kbd, KEY_LEFTMETA, false);
+            qkbd_state_key_event(kbd, KEY_RIGHTMETA, false);
         }
     }
 
@@ -954,34 +926,34 @@ - (bool) handleEventLocked:(NSEvent *)event
             switch ([event keyCode]) {
                 case kVK_Shift:
                     if (!!(modifiers & NSEventModifierFlagShift)) {
-                        [self toggleKey:Q_KEY_CODE_SHIFT];
+                        [self toggleKey:KEY_LEFTSHIFT];
                     }
                     break;
 
                 case kVK_RightShift:
                     if (!!(modifiers & NSEventModifierFlagShift)) {
-                        [self toggleKey:Q_KEY_CODE_SHIFT_R];
+                        [self toggleKey:KEY_RIGHTSHIFT];
                     }
                     break;
 
                 case kVK_Control:
                     if (!!(modifiers & NSEventModifierFlagControl)) {
-                        [self toggleKey:Q_KEY_CODE_CTRL];
+                        [self toggleKey:KEY_LEFTCTRL];
                     }
                     break;
 
                 case kVK_RightControl:
                     if (!!(modifiers & NSEventModifierFlagControl)) {
-                        [self toggleKey:Q_KEY_CODE_CTRL_R];
+                        [self toggleKey:KEY_RIGHTCTRL];
                     }
                     break;
 
                 case kVK_Option:
                     if (!!(modifiers & NSEventModifierFlagOption)) {
                         if (swap_opt_cmd) {
-                            [self toggleKey:Q_KEY_CODE_META_L];
+                            [self toggleKey:KEY_LEFTMETA];
                         } else {
-                            [self toggleKey:Q_KEY_CODE_ALT];
+                            [self toggleKey:KEY_LEFTALT];
                         }
                     }
                     break;
@@ -989,9 +961,9 @@ - (bool) handleEventLocked:(NSEvent *)event
                 case kVK_RightOption:
                     if (!!(modifiers & NSEventModifierFlagOption)) {
                         if (swap_opt_cmd) {
-                            [self toggleKey:Q_KEY_CODE_META_R];
+                            [self toggleKey:KEY_RIGHTMETA];
                         } else {
-                            [self toggleKey:Q_KEY_CODE_ALT_R];
+                            [self toggleKey:KEY_RIGHTALT];
                         }
                     }
                     break;
@@ -1002,9 +974,9 @@ - (bool) handleEventLocked:(NSEvent *)event
                         !!(modifiers & NSEventModifierFlagCommand) &&
                         left_command_key_enabled) {
                         if (swap_opt_cmd) {
-                            [self toggleKey:Q_KEY_CODE_ALT];
+                            [self toggleKey:KEY_LEFTALT];
                         } else {
-                            [self toggleKey:Q_KEY_CODE_META_L];
+                            [self toggleKey:KEY_LEFTMETA];
                         }
                     }
                     break;
@@ -1013,16 +985,16 @@ - (bool) handleEventLocked:(NSEvent *)event
                     if (isMouseGrabbed &&
                         !!(modifiers & NSEventModifierFlagCommand)) {
                         if (swap_opt_cmd) {
-                            [self toggleKey:Q_KEY_CODE_ALT_R];
+                            [self toggleKey:KEY_RIGHTALT];
                         } else {
-                            [self toggleKey:Q_KEY_CODE_META_R];
+                            [self toggleKey:KEY_RIGHTMETA];
                         }
                     }
                     break;
             }
             return true;
         case NSEventTypeKeyDown:
-            keycode = cocoa_keycode_to_qemu([event keyCode]);
+            keycode = cocoa_keycode_to_linux([event keyCode]);
 
             // forward command key combos to the host UI unless the mouse is grabbed
             if (!isMouseGrabbed && ([event modifierFlags] & NSEventModifierFlagCommand)) {
@@ -1052,15 +1024,13 @@ - (bool) handleEventLocked:(NSEvent *)event
             }
 
             if (qemu_console_is_graphic(dcl.con)) {
-                qkbd_state_key_event(kbd,
-                                     qemu_input_map_qcode_to_linux[keycode],
-                                     true);
+                qkbd_state_key_event(kbd, keycode, true);
             } else {
                 [self handleMonitorInput: event];
             }
             return true;
         case NSEventTypeKeyUp:
-            keycode = cocoa_keycode_to_qemu([event keyCode]);
+            keycode = cocoa_keycode_to_linux([event keyCode]);
 
             // don't pass the guest a spurious key-up if we treated this
             // command-key combo as a host UI action
@@ -1069,9 +1039,7 @@ - (bool) handleEventLocked:(NSEvent *)event
             }
 
             if (qemu_console_is_graphic(dcl.con)) {
-                qkbd_state_key_event(kbd,
-                                     qemu_input_map_qcode_to_linux[keycode],
-                                     false);
+                qkbd_state_key_event(kbd, keycode, false);
             }
             return true;
         case NSEventTypeScrollWheel:
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 26/38] ui/dbus: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (24 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 25/38] ui/cocoa: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 27/38] ui/gtk: " marcandre.lureau
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-18-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/dbus-console.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 24f4542f312..21eceb24362 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -339,11 +339,11 @@ dbus_kbd_press(DBusDisplayConsole *ddc,
                GDBusMethodInvocation *invocation,
                guint arg_keycode)
 {
-    QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
+    unsigned int lnx = qemu_input_key_number_to_linux(arg_keycode);
 
     trace_dbus_kbd_press(arg_keycode);
 
-    qkbd_state_key_event(ddc->kbd, qemu_input_map_qcode_to_linux[qcode], true);
+    qkbd_state_key_event(ddc->kbd, lnx, true);
 
     qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation);
 
@@ -355,11 +355,11 @@ dbus_kbd_release(DBusDisplayConsole *ddc,
                  GDBusMethodInvocation *invocation,
                  guint arg_keycode)
 {
-    QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
+    unsigned int lnx = qemu_input_key_number_to_linux(arg_keycode);
 
     trace_dbus_kbd_release(arg_keycode);
 
-    qkbd_state_key_event(ddc->kbd, qemu_input_map_qcode_to_linux[qcode], false);
+    qkbd_state_key_event(ddc->kbd, lnx, false);
 
     qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation);
 
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 27/38] ui/gtk: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (25 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 26/38] ui/dbus: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 28/38] ui/input-barrier: " marcandre.lureau
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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>
---
 ui/x_keymap.h   |  3 ++-
 ui/gtk.c        | 51 ++++++++++++++++++++++++++++---------------------
 ui/x_keymap.c   | 24 ++++++++++++-----------
 ui/trace-events |  2 +-
 4 files changed, 45 insertions(+), 35 deletions(-)

diff --git a/ui/x_keymap.h b/ui/x_keymap.h
index 0395e335fff..0d58459dd21 100644
--- a/ui/x_keymap.h
+++ b/ui/x_keymap.h
@@ -27,6 +27,7 @@
 
 #include <X11/Xlib.h>
 
-const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen);
+const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen,
+                                          bool *evdev);
 
 #endif
diff --git a/ui/gtk.c b/ui/gtk.c
index 757ee80fa6a..9f9b2416c8a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -55,6 +55,7 @@
 #include <math.h>
 
 #include "trace.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/input.h"
 #include "system/runstate.h"
 #include "system/system.h"
@@ -120,6 +121,7 @@
 
 static const guint16 *keycode_map;
 static size_t keycode_maplen;
+static bool keycode_xorgevdev;
 
 struct VCChardev {
     Chardev parent;
@@ -1211,39 +1213,42 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
     return TRUE;
 }
 
-static const guint16 *gd_get_keymap(size_t *maplen)
+static const guint16 *gd_get_keymap(size_t *maplen, bool *xorgevdev)
 {
     GdkDisplay *dpy = gdk_display_get_default();
 
+    *maplen = 0;
+    *xorgevdev = false;
+
 #ifdef GDK_WINDOWING_X11
     if (GDK_IS_X11_DISPLAY(dpy)) {
         trace_gd_keymap_windowing("x11");
         return qemu_xkeymap_mapping_table(
-            gdk_x11_display_get_xdisplay(dpy), maplen);
+            gdk_x11_display_get_xdisplay(dpy), maplen, xorgevdev);
     }
 #endif
 
 #ifdef GDK_WINDOWING_WAYLAND
     if (GDK_IS_WAYLAND_DISPLAY(dpy)) {
         trace_gd_keymap_windowing("wayland");
-        *maplen = qemu_input_map_xorgevdev_to_qcode_len;
-        return qemu_input_map_xorgevdev_to_qcode;
+        *xorgevdev = true;
+        return NULL;
     }
 #endif
 
 #ifdef GDK_WINDOWING_WIN32
     if (GDK_IS_WIN32_DISPLAY(dpy)) {
         trace_gd_keymap_windowing("win32");
-        *maplen = qemu_input_map_atset1_to_qcode_len;
-        return qemu_input_map_atset1_to_qcode;
+        *maplen = qemu_input_map_atset1_to_linux_len;
+        return qemu_input_map_atset1_to_linux;
     }
 #endif
 
 #ifdef GDK_WINDOWING_QUARTZ
     if (GDK_IS_QUARTZ_DISPLAY(dpy)) {
         trace_gd_keymap_windowing("quartz");
-        *maplen = qemu_input_map_osx_to_qcode_len;
-        return qemu_input_map_osx_to_qcode;
+        *maplen = qemu_input_map_osx_to_linux_len;
+        return qemu_input_map_osx_to_linux;
     }
 #endif
 
@@ -1253,8 +1258,8 @@ static const guint16 *gd_get_keymap(size_t *maplen)
         g_warning("experimental: using broadway, x11 virtual keysym\n"
                   "mapping - with very limited support. See also\n"
                   "https://bugzilla.gnome.org/show_bug.cgi?id=700105");
-        *maplen = qemu_input_map_x11_to_qcode_len;
-        return qemu_input_map_x11_to_qcode;
+        *maplen = qemu_input_map_x11_to_linux_len;
+        return qemu_input_map_x11_to_linux;
     }
 #endif
 
@@ -1269,8 +1274,11 @@ static const guint16 *gd_get_keymap(size_t *maplen)
 }
 
 
-static int gd_map_keycode(int scancode)
+static unsigned int gd_map_keycode(int scancode)
 {
+    if (keycode_xorgevdev) {
+        return scancode < 8 ? KEY_RESERVED : scancode - 8;
+    }
     if (!keycode_map) {
         return 0;
     }
@@ -1307,12 +1315,12 @@ static gboolean gd_text_key_down(GtkWidget *widget,
     QemuTextConsole *con = QEMU_TEXT_CONSOLE(vc->gfx.dcl.con);
 
     if (key->keyval == GDK_KEY_Delete) {
-        qemu_text_console_put_qcode(con, Q_KEY_CODE_DELETE, false);
+        qemu_text_console_put_linux(con, KEY_DELETE, false);
     } else if (key->length) {
         qemu_text_console_put_string(con, key->string, key->length);
     } else {
-        int qcode = gd_map_keycode(gd_get_keycode(key));
-        qemu_text_console_put_qcode(con, qcode, false);
+        unsigned int lnx = gd_map_keycode(gd_get_keycode(key));
+        qemu_text_console_put_linux(con, lnx, false);
     }
     return TRUE;
 }
@@ -1320,7 +1328,8 @@ static gboolean gd_text_key_down(GtkWidget *widget,
 static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
 {
     VirtualConsole *vc = opaque;
-    int keycode, qcode;
+    int keycode;
+    unsigned int lnx;
 
 #ifdef G_OS_WIN32
     /* 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)
         || key->hardware_keycode == VK_PAUSE
 #endif
         ) {
-        qkbd_state_key_event(vc->gfx.kbd,
-                             qemu_input_map_qcode_to_linux[Q_KEY_CODE_PAUSE],
+        qkbd_state_key_event(vc->gfx.kbd, KEY_PAUSE,
                              key->type == GDK_KEY_PRESS);
         return TRUE;
     }
 
     keycode = gd_get_keycode(key);
-    qcode = gd_map_keycode(keycode);
+    lnx = gd_map_keycode(keycode);
 
-    trace_gd_key_event(vc->label, keycode, qemu_input_map_qcode_to_linux[qcode],
+    trace_gd_key_event(vc->label, keycode, lnx,
                        (key->type == GDK_KEY_PRESS) ? "down" : "up");
 
-    qkbd_state_key_event(vc->gfx.kbd, qemu_input_map_qcode_to_linux[qcode],
-                         key->type == GDK_KEY_PRESS);
+    qkbd_state_key_event(vc->gfx.kbd, lnx, key->type == GDK_KEY_PRESS);
 
     return TRUE;
 }
@@ -2660,7 +2667,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
 #endif
     }
 
-    keycode_map = gd_get_keymap(&keycode_maplen);
+    keycode_map = gd_get_keymap(&keycode_maplen, &keycode_xorgevdev);
 
 #if defined(CONFIG_VTE)
     type_register_static(&char_gd_vc_type_info);
diff --git a/ui/x_keymap.c b/ui/x_keymap.c
index 2ce7b899615..f7dc2edb91d 100644
--- a/ui/x_keymap.c
+++ b/ui/x_keymap.c
@@ -52,11 +52,12 @@ static gboolean check_for_xquartz(Display *dpy)
     return match;
 }
 
-const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen)
+const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen,
+                                          bool *evdev)
 {
     XkbDescPtr desc;
     const gchar *keycodes = NULL;
-    const guint16 *map;
+    const guint16 *map = NULL;
 
     /* There is no easy way to determine what X11 server
      * and platform & keyboard driver is in use. Thus we
@@ -81,24 +82,26 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen)
         XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
     }
 
+    *maplen = 0;
+    *evdev = false;
+
     if (check_for_xwin(dpy)) {
         trace_xkeymap_keymap("xwin");
-        *maplen = qemu_input_map_xorgxwin_to_qcode_len;
-        map = qemu_input_map_xorgxwin_to_qcode;
+        *maplen = qemu_input_map_xorgxwin_to_linux_len;
+        map = qemu_input_map_xorgxwin_to_linux;
     } else if (check_for_xquartz(dpy)) {
         trace_xkeymap_keymap("xquartz");
-        *maplen = qemu_input_map_xorgxquartz_to_qcode_len;
-        map = qemu_input_map_xorgxquartz_to_qcode;
+        *maplen = qemu_input_map_xorgxquartz_to_linux_len;
+        map = qemu_input_map_xorgxquartz_to_linux;
     } else if ((keycodes && g_str_has_prefix(keycodes, "evdev")) ||
                (XKeysymToKeycode(dpy, XK_Page_Up) == 0x70)) {
         trace_xkeymap_keymap("evdev");
-        *maplen = qemu_input_map_xorgevdev_to_qcode_len;
-        map = qemu_input_map_xorgevdev_to_qcode;
+        *evdev = true;
     } else if ((keycodes && g_str_has_prefix(keycodes, "xfree86")) ||
                (XKeysymToKeycode(dpy, XK_Page_Up) == 0x63)) {
         trace_xkeymap_keymap("kbd");
-        *maplen = qemu_input_map_xorgkbd_to_qcode_len;
-        map = qemu_input_map_xorgkbd_to_qcode;
+        *maplen = qemu_input_map_xorgkbd_to_linux_len;
+        map = qemu_input_map_xorgkbd_to_linux;
     } else {
         trace_xkeymap_keymap("NULL");
         g_warning("Unknown X11 keycode mapping '%s'.\n"
@@ -110,7 +113,6 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen)
                   "  - xprop -root\n"
                   "  - xdpyinfo\n",
                   keycodes ? keycodes : "<null>");
-        map = NULL;
     }
     if (keycodes) {
         XFree((void *)keycodes);
diff --git a/ui/trace-events b/ui/trace-events
index 1c0d96a92c3..237f5a65af2 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -22,7 +22,7 @@ ppm_save(int fd, void *image) "fd=%d image=%p"
 # gtk.c
 gd_switch(const char *tab, int width, int height) "tab=%s, width=%d, height=%d"
 gd_update(const char *tab, int x, int y, int w, int h) "tab=%s, x=%d, y=%d, w=%d, h=%d"
-gd_key_event(const char *tab, int gdk_keycode, int qkeycode, const char *action) "tab=%s, translated GDK keycode %d to QKeyCode %d (%s)"
+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)"
 gd_grab(const char *tab, const char *device, const char *reason) "tab=%s, dev=%s, reason=%s"
 gd_ungrab(const char *tab, const char *device) "tab=%s, dev=%s"
 gd_keymap_windowing(const char *name) "backend=%s"
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 28/38] ui/input-barrier: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (26 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 27/38] ui/gtk: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 29/38] ui/input-legacy: " marcandre.lureau
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-20-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/input-barrier.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/ui/input-barrier.c b/ui/input-barrier.c
index 042f63cc5a1..d07027114af 100644
--- a/ui/input-barrier.c
+++ b/ui/input-barrier.c
@@ -84,11 +84,11 @@ static const char *cmd_names[] = {
 
 static kbd_layout_t *kbd_layout;
 
-static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode)
+static unsigned int input_barrier_to_linux(uint16_t keyid, uint16_t keycode)
 {
     /* keycode is optional, if it is not provided use keyid */
-    if (keycode && keycode <= qemu_input_map_xorgkbd_to_qcode_len) {
-        return qemu_input_map_xorgkbd_to_qcode[keycode];
+    if (keycode && keycode <= qemu_input_map_xorgkbd_to_linux_len) {
+        return qemu_input_map_xorgkbd_to_linux[keycode];
     }
 
     if (keyid >= 0xE000 && keyid <= 0xEFFF) {
@@ -99,10 +99,10 @@ static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode)
     if (kbd_layout) {
         keycode = keysym2scancode(kbd_layout, keyid, NULL, false);
 
-        return qemu_input_key_number_to_qcode(keycode);
+        return qemu_input_key_number_to_linux(keycode);
     }
 
-    return qemu_input_map_x11_to_qcode[keyid];
+    return qemu_input_map_x11_to_linux[keyid];
 }
 
 static int input_barrier_to_mouse(uint8_t buttonid)
@@ -431,23 +431,23 @@ static gboolean writecmd(InputBarrier *ib, struct barrierMsg *msg)
 
     /* keyboard */
     case barrierCmdDKeyDown:
-        qemu_input_event_send_key_qcode(NULL,
-                        input_barrier_to_qcode(msg->key.keyid, msg->key.button),
+        qemu_input_event_send_key_linux(NULL,
+                        input_barrier_to_linux(msg->key.keyid, msg->key.button),
                                         true);
         break;
     case barrierCmdDKeyRepeat:
         for (i = 0; i < msg->repeat.repeat; i++) {
-            qemu_input_event_send_key_qcode(NULL,
-                  input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
+            qemu_input_event_send_key_linux(NULL,
+                  input_barrier_to_linux(msg->repeat.keyid, msg->repeat.button),
                                             false);
-            qemu_input_event_send_key_qcode(NULL,
-                  input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
+            qemu_input_event_send_key_linux(NULL,
+                  input_barrier_to_linux(msg->repeat.keyid, msg->repeat.button),
                                             true);
         }
         break;
     case barrierCmdDKeyUp:
-        qemu_input_event_send_key_qcode(NULL,
-                        input_barrier_to_qcode(msg->key.keyid, msg->key.button),
+        qemu_input_event_send_key_linux(NULL,
+                        input_barrier_to_linux(msg->key.keyid, msg->key.button),
                                         false);
         break;
     default:
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 29/38] ui/input-legacy: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (27 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 28/38] ui/input-barrier: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 30/38] ui/input-linux: " marcandre.lureau
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-21-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/input-legacy.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index e2b48dd8f0a..193c9ae2ef9 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -71,23 +71,11 @@ int index_from_key(const char *key, size_t key_length)
     return i;
 }
 
-static KeyValue *copy_key_value(KeyValue *src)
-{
-    KeyValue *dst = g_new(KeyValue, 1);
-    memcpy(dst, src, sizeof(*src));
-    if (dst->type == KEY_VALUE_KIND_NUMBER) {
-        QKeyCode code = qemu_input_key_number_to_qcode(dst->u.number.data);
-        dst->type = KEY_VALUE_KIND_QCODE;
-        dst->u.qcode.data = code;
-    }
-    return dst;
-}
-
 void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
                   Error **errp)
 {
     KeyValueList *p;
-    KeyValue **up = NULL;
+    unsigned int *up = NULL;
     int count = 0;
 
     if (!has_hold_time) {
@@ -95,15 +83,15 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
     }
 
     for (p = keys; p != NULL; p = p->next) {
-        qemu_input_event_send_key(NULL, copy_key_value(p->value), true);
-        qemu_input_event_send_key_delay(hold_time);
         up = g_realloc(up, sizeof(*up) * (count+1));
-        up[count] = copy_key_value(p->value);
+        up[count] = qemu_input_key_value_to_linux(p->value);
+        qemu_input_event_send_key_linux(NULL, up[count], true);
+        qemu_input_event_send_key_delay(hold_time);
         count++;
     }
     while (count) {
         count--;
-        qemu_input_event_send_key(NULL, up[count], false);
+        qemu_input_event_send_key_linux(NULL, up[count], false);
         qemu_input_event_send_key_delay(hold_time);
     }
     g_free(up);
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 30/38] ui/input-linux: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (28 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 29/38] ui/input-legacy: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 31/38] ui/keymaps: " marcandre.lureau
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-22-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/input-linux.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ui/input-linux.c b/ui/input-linux.c
index 74bc8511428..f4eee1ffd7e 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -166,8 +166,7 @@ static void input_linux_handle_keyboard(InputLinux *il,
 
         /* send event to guest when grab is active */
         if (il->grab_active && !input_linux_should_skip(il, event)) {
-            int qcode = qemu_input_linux_to_qcode(event->code);
-            qemu_input_event_send_key_qcode(NULL, qcode, event->value);
+            qemu_input_event_send_key_linux(NULL, event->code, event->value);
         }
 
         /* hotkey -> record switch request ... */
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 31/38] ui/keymaps: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (29 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 30/38] ui/input-linux: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 32/38] ui/sdl2: " marcandre.lureau
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-23-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/keymaps.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ui/keymaps.c b/ui/keymaps.c
index a448efab320..d145b5dd3a8 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -255,9 +255,8 @@ int keysym2scancode(kbd_layout_t *k, int keysym,
          * On keyup: Try find a key which is actually down.
          */
         for (i = 0; i < keysym2code->count; i++) {
-            QKeyCode qcode = qemu_input_key_number_to_qcode
+            unsigned int lnx = qemu_input_key_number_to_linux
                 (keysym2code->keycodes[i]);
-            unsigned int lnx = qemu_input_map_qcode_to_linux[qcode];
             if (kbd && qkbd_state_key_get(kbd, lnx)) {
                 return keysym2code->keycodes[i];
             }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 32/38] ui/sdl2: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (30 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 31/38] ui/keymaps: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 33/38] ui/spice: " marcandre.lureau
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-24-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/sdl2-input.c | 18 +++++++++---------
 ui/trace-events |  2 +-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c
index fdbdc427dc9..7bebc3f3e5c 100644
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -24,6 +24,7 @@
 /* Ported SDL 1.2 code to 2.0 by Dave Airlie. */
 
 #include "qemu/osdep.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "ui/input.h"
 #include "ui/sdl2.h"
@@ -32,28 +33,27 @@
 void sdl2_process_key(struct sdl2_console *scon,
                       SDL_KeyboardEvent *ev)
 {
-    int qcode;
+    unsigned int lnx;
     QemuConsole *con = scon->dcl.con;
 
-    if (ev->keysym.scancode >= qemu_input_map_usb_to_qcode_len) {
+    if (ev->keysym.scancode >= qemu_input_map_usb_to_linux_len) {
         return;
     }
-    qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode];
-    trace_sdl2_process_key(ev->keysym.scancode, qcode,
+    lnx = qemu_input_map_usb_to_linux[ev->keysym.scancode];
+    trace_sdl2_process_key(ev->keysym.scancode, lnx,
                            ev->type == SDL_KEYDOWN ? "down" : "up");
-    qkbd_state_key_event(scon->kbd, qemu_input_map_qcode_to_linux[qcode],
-                         ev->type == SDL_KEYDOWN);
+    qkbd_state_key_event(scon->kbd, lnx, ev->type == SDL_KEYDOWN);
 
     if (QEMU_IS_TEXT_CONSOLE(con)) {
         QemuTextConsole *s = QEMU_TEXT_CONSOLE(con);
         bool ctrl = qkbd_state_modifier_get(scon->kbd, QKBD_MOD_CTRL);
         if (ev->type == SDL_KEYDOWN) {
-            switch (qcode) {
-            case Q_KEY_CODE_RET:
+            switch (lnx) {
+            case KEY_ENTER:
                 qemu_text_console_put_keysym(s, '\n');
                 break;
             default:
-                qemu_text_console_put_qcode(s, qcode, ctrl);
+                qemu_text_console_put_linux(s, lnx, ctrl);
                 break;
             }
         }
diff --git a/ui/trace-events b/ui/trace-events
index 237f5a65af2..339a61f3415 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -135,7 +135,7 @@ input_event_mtt(int conidx, const char *axis, int value) "con %d, axis %s, value
 input_event_sync(void) ""
 
 # sdl2-input.c
-sdl2_process_key(int sdl_scancode, int qcode, const char *action) "translated SDL scancode %d to QKeyCode %d (%s)"
+sdl2_process_key(int sdl_scancode, unsigned int lnx, const char *action) "translated SDL scancode %d to Linux scancode %u (%s)"
 
 # spice-display.c
 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"
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 33/38] ui/spice: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (31 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 32/38] ui/sdl2: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-25  6:32 ` [PULL v3 34/38] ui/vnc: " marcandre.lureau
  2026-05-26 14:59 ` [PULL v3 00/38] Ui patches Stefan Hajnoczi
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-25-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/spice-input.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ui/spice-input.c b/ui/spice-input.c
index a5c5d78474e..f0bb915fd77 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -20,6 +20,7 @@
 #include <spice.h>
 #include <spice/enums.h>
 
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/qemu-spice.h"
 #include "ui/console.h"
 #include "keymaps.h"
@@ -61,7 +62,7 @@ static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode)
     if (scancode == pauseseq[kbd->pauseseq]) {
         kbd->pauseseq++;
         if (kbd->pauseseq == G_N_ELEMENTS(pauseseq)) {
-            qemu_input_event_send_key_qcode(NULL, Q_KEY_CODE_PAUSE, true);
+            qemu_input_event_send_key_linux(NULL, KEY_PAUSE, true);
             kbd->pauseseq = 0;
         }
         return;
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PULL v3 34/38] ui/vnc: Use Linux key codes
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (32 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 33/38] ui/spice: " marcandre.lureau
@ 2026-05-25  6:32 ` marcandre.lureau
  2026-05-26 14:59 ` [PULL v3 00/38] Ui patches Stefan Hajnoczi
  34 siblings, 0 replies; 36+ messages in thread
From: marcandre.lureau @ 2026-05-25  6:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Akihiko Odaki, Marc-André Lureau

From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

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-26-7c9e4c7abe34@rsg.ci.i.u-tokyo.ac.jp>
---
 ui/vnc.c | 29 +++++++++++++----------------
 1 file changed, 13 insertions(+), 16 deletions(-)

diff --git a/ui/vnc.c b/ui/vnc.c
index 0a8c5ab0d2d..253b1a9f634 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -43,6 +43,7 @@
 #include "qapi/qapi-events-ui.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-ui.h"
+#include "standard-headers/linux/input-event-codes.h"
 #include "ui/console.h"
 #include "ui/input.h"
 #include "crypto/hash.h"
@@ -1797,13 +1798,10 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
     qemu_input_event_sync();
 }
 
-static void press_key(VncState *vs, QKeyCode qcode)
+static void press_key(VncState *vs, unsigned int lnx)
 {
-    qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
-                         true);
-
-    qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
-                         false);
+    qkbd_state_key_event(vs->vd->kbd, lnx, true);
+    qkbd_state_key_event(vs->vd->kbd, lnx, false);
 }
 
 static void vnc_led_state_change(VncState *vs)
@@ -1844,15 +1842,15 @@ static void kbd_leds(void *opaque, int ledstate)
 
 static void do_key_event(VncState *vs, int down, int keycode, int sym)
 {
-    QKeyCode qcode = qemu_input_key_number_to_qcode(keycode);
+    unsigned int lnx = qemu_input_key_number_to_linux(keycode);
 
     /* QEMU console switch */
-    switch (qcode) {
-    case Q_KEY_CODE_1 ... Q_KEY_CODE_9: /* '1' to '9' keys */
+    switch (lnx) {
+    case KEY_1 ... KEY_9: /* '1' to '9' keys */
         if (down &&
             qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_CTRL) &&
             qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_ALT)) {
-            QemuConsole *con = qemu_console_lookup_by_index(qcode - Q_KEY_CODE_1);
+            QemuConsole *con = qemu_console_lookup_by_index(lnx - KEY_1);
             if (con) {
                 qemu_console_unregister_listener(&vs->vd->dcl);
                 qkbd_state_switch_console(vs->vd->kbd, con);
@@ -1877,12 +1875,12 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
         if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
             if (!qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK)) {
                 trace_vnc_key_sync_numlock(true);
-                press_key(vs, Q_KEY_CODE_NUM_LOCK);
+                press_key(vs, KEY_NUMLOCK);
             }
         } else {
             if (qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK)) {
                 trace_vnc_key_sync_numlock(false);
-                press_key(vs, Q_KEY_CODE_NUM_LOCK);
+                press_key(vs, KEY_NUMLOCK);
             }
         }
     }
@@ -1900,18 +1898,17 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
         if (capslock) {
             if (uppercase == shift) {
                 trace_vnc_key_sync_capslock(false);
-                press_key(vs, Q_KEY_CODE_CAPS_LOCK);
+                press_key(vs, KEY_CAPSLOCK);
             }
         } else {
             if (uppercase != shift) {
                 trace_vnc_key_sync_capslock(true);
-                press_key(vs, Q_KEY_CODE_CAPS_LOCK);
+                press_key(vs, KEY_CAPSLOCK);
             }
         }
     }
 
-    qkbd_state_key_event(vs->vd->kbd, qemu_input_map_qcode_to_linux[qcode],
-                         down);
+    qkbd_state_key_event(vs->vd->kbd, lnx, down);
     if (QEMU_IS_TEXT_CONSOLE(vs->vd->dcl.con)) {
         QemuTextConsole *con = QEMU_TEXT_CONSOLE(vs->vd->dcl.con);
         bool numlock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK);
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PULL v3 00/38] Ui patches
  2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
                   ` (33 preceding siblings ...)
  2026-05-25  6:32 ` [PULL v3 34/38] ui/vnc: " marcandre.lureau
@ 2026-05-26 14:59 ` Stefan Hajnoczi
  34 siblings, 0 replies; 36+ messages in thread
From: Stefan Hajnoczi @ 2026-05-26 14:59 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: qemu-devel, stefanha, Marc-André Lureau

[-- Attachment #1: Type: text/plain, Size: 116 bytes --]

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2026-05-26 14:59 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-25  6:31 [PULL v3 00/38] Ui patches marcandre.lureau
2026-05-25  6:31 ` [PULL v3 01/38] ui/vt100: Standardize on uint8_t for "ch" byte variables marcandre.lureau
2026-05-25  6:31 ` [PULL v3 02/38] ui/vt100: Take byte as uint8_t in bh_utf8_decode() marcandre.lureau
2026-05-25  6:31 ` [PULL v3 03/38] ui/vt100: add vt100_fini() check marcandre.lureau
2026-05-25  6:31 ` [PULL v3 04/38] ui/vnc: fix OOB read access in VNC SASL mechname array marcandre.lureau
2026-05-25  6:31 ` [PULL v3 05/38] ui/vnc: fix OOB write in VNC stats array marcandre.lureau
2026-05-25  6:31 ` [PULL v3 06/38] ui/vnc: fix OOB write in lossy rect worker code marcandre.lureau
2026-05-25  6:31 ` [PULL v3 07/38] ui/vnc: fix OOB read updating VNC update frequency stats marcandre.lureau
2026-05-25  6:31 ` [PULL v3 08/38] ui: fix validation of VNC extended clipboard data length marcandre.lureau
2026-05-25  6:31 ` [PULL v3 09/38] ui/input: Introduce QemuInputEvent typedef marcandre.lureau
2026-05-25  6:31 ` [PULL v3 10/38] ui/input: Remove QAPI wrappers from QemuInputEvent marcandre.lureau
2026-05-25  6:31 ` [PULL v3 11/38] ui/input: Store QKeyCode directly in QemuInputKeyEvent marcandre.lureau
2026-05-25  6:31 ` [PULL v3 12/38] ui/input: Use Linux key codes for internal key events marcandre.lureau
2026-05-25  6:31 ` [PULL v3 13/38] ui/input: Prohibit sending KEY_RESERVED marcandre.lureau
2026-05-25  6:31 ` [PULL v3 14/38] ui/console: Add qemu_text_console_put_linux() marcandre.lureau
2026-05-25  6:31 ` [PULL v3 15/38] ui/kbd-state: Use Linux key codes marcandre.lureau
2026-05-25  6:31 ` [PULL v3 16/38] hw/arm/musicpal: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 17/38] hw/char/escc: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 18/38] hw/display/xenfb: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 19/38] hw/input/adb-kbd: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 20/38] hw/input/hid: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 21/38] hw/input/ps2: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 22/38] hw/input/virtio-input: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 23/38] hw/m68k/next-kbd: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 24/38] replay: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 25/38] ui/cocoa: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 26/38] ui/dbus: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 27/38] ui/gtk: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 28/38] ui/input-barrier: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 29/38] ui/input-legacy: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 30/38] ui/input-linux: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 31/38] ui/keymaps: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 32/38] ui/sdl2: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 33/38] ui/spice: " marcandre.lureau
2026-05-25  6:32 ` [PULL v3 34/38] ui/vnc: " marcandre.lureau
2026-05-26 14:59 ` [PULL v3 00/38] Ui patches Stefan Hajnoczi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.