Files
qemu/ui/input-keymap.c
Akihiko Odaki 184c07600d ui/input: Use Linux key codes for internal key events
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>
2026-05-25 01:00:54 +04:00

123 lines
3.8 KiB
C

#include "qemu/osdep.h"
#include "keymaps.h"
#include "ui/input.h"
#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)
{
if (lnx >= qemu_input_map_linux_to_qcode_len) {
return 0;
}
return qemu_input_map_linux_to_qcode[lnx];
}
int qemu_input_key_value_to_number(const KeyValue *value)
{
if (value->type == KEY_VALUE_KIND_QCODE) {
if (value->u.qcode.data >= qemu_input_map_qcode_to_qnum_len) {
return 0;
}
return qemu_input_map_qcode_to_qnum[value->u.qcode.data];
} else {
assert(value->type == KEY_VALUE_KIND_NUMBER);
return value->u.number.data;
}
}
int qemu_input_key_number_to_qcode(unsigned int nr)
{
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_linux[nr];
}
int qemu_input_key_value_to_qcode(const KeyValue *value)
{
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)
{
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 (lnx == KEY_PAUSE) {
/* specific case */
int v = down ? 0 : 0x80;
codes[count++] = 0xe1;
codes[count++] = 0x1d | v;
codes[count++] = 0x45 | v;
return count;
}
if (keycode & SCANCODE_GREY) {
codes[count++] = SCANCODE_EMUL0;
keycode &= ~SCANCODE_GREY;
}
if (!down) {
keycode |= SCANCODE_UP;
}
codes[count++] = keycode;
return count;
}