fa9ddb1caf
Commit 2523baf7fb
("qemu-keymap: Make references to allocations
static") made references to allocations static to ensure LeakSanitizer
can track them. This trick unfortunately did not work with gcc version
14.0.1; that compiler is clever enough to know that the value of the
"state" variable is only referred in the current execution of the
function and to put it on the stack.
Release references to allocations and suppress the error once for all.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
269 lines
7.6 KiB
C
269 lines
7.6 KiB
C
/*
|
|
* QEMU keymap utility
|
|
*
|
|
* Copyright Red Hat, Inc. 2017
|
|
*
|
|
* Authors:
|
|
* Gerd Hoffmann <kraxel@redhat.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/notify.h"
|
|
#include "ui/input.h"
|
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
struct xkb_rule_names names = {
|
|
.rules = NULL,
|
|
.model = "pc105",
|
|
.layout = "us",
|
|
.variant = NULL,
|
|
.options = NULL,
|
|
};
|
|
|
|
static xkb_mod_mask_t shift;
|
|
static xkb_mod_mask_t ctrl;
|
|
static xkb_mod_mask_t altgr;
|
|
static xkb_mod_mask_t numlock;
|
|
|
|
static FILE *outfile;
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static uint32_t qcode_to_number(uint32_t qcode)
|
|
{
|
|
KeyValue keyvalue;
|
|
uint32_t number;
|
|
|
|
keyvalue.type = KEY_VALUE_KIND_QCODE;
|
|
keyvalue.u.qcode.data = qcode;
|
|
number = qemu_input_key_value_to_number(&keyvalue);
|
|
assert(number != 0);
|
|
return number;
|
|
}
|
|
|
|
static void print_sym(xkb_keysym_t sym, uint32_t qcode, const char *mod)
|
|
{
|
|
char name[64];
|
|
|
|
if (sym == XKB_KEY_NoSymbol) {
|
|
return;
|
|
}
|
|
xkb_keysym_get_name(sym, name, sizeof(name));
|
|
|
|
/* TODO: make ui/keymap.c parser accept QKeyCode names */
|
|
fprintf(outfile, "%s 0x%02x%s\n", name, qcode_to_number(qcode), mod);
|
|
}
|
|
|
|
static void walk_map(struct xkb_keymap *map, xkb_keycode_t code, void *data)
|
|
{
|
|
struct xkb_state *state = data;
|
|
xkb_keysym_t kbase, knumlock, kshift, kaltgr, kaltgrshift;
|
|
uint32_t evdev, qcode;
|
|
char name[64];
|
|
|
|
fprintf(outfile, "\n");
|
|
|
|
/*
|
|
* map xkb keycode -> QKeyCode
|
|
*
|
|
* xkb keycode is linux evdev shifted by 8
|
|
*/
|
|
evdev = code - 8;
|
|
qcode = qemu_input_linux_to_qcode(evdev);
|
|
if (qcode == Q_KEY_CODE_UNMAPPED) {
|
|
xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0);
|
|
kbase = xkb_state_key_get_one_sym(state, code);
|
|
xkb_keysym_get_name(kbase, name, sizeof(name));
|
|
fprintf(outfile, "# evdev %d (0x%x): no evdev -> QKeyCode mapping"
|
|
" (xkb keysym %s)\n", evdev, evdev, name);
|
|
return;
|
|
}
|
|
fprintf(outfile, "# evdev %d (0x%x), QKeyCode \"%s\", number 0x%x\n",
|
|
evdev, evdev,
|
|
QKeyCode_str(qcode),
|
|
qcode_to_number(qcode));
|
|
|
|
/*
|
|
* check which modifier states generate which keysyms
|
|
*/
|
|
xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0);
|
|
kbase = xkb_state_key_get_one_sym(state, code);
|
|
print_sym(kbase, qcode, "");
|
|
|
|
xkb_state_update_mask(state, 0, 0, numlock, 0, 0, 0);
|
|
knumlock = xkb_state_key_get_one_sym(state, code);
|
|
if (kbase != knumlock) {
|
|
print_sym(knumlock, qcode, " numlock");
|
|
}
|
|
|
|
xkb_state_update_mask(state, shift, 0, 0, 0, 0, 0);
|
|
kshift = xkb_state_key_get_one_sym(state, code);
|
|
if (kbase != kshift && knumlock != kshift) {
|
|
print_sym(kshift, qcode, " shift");
|
|
}
|
|
|
|
xkb_state_update_mask(state, altgr, 0, 0, 0, 0, 0);
|
|
kaltgr = xkb_state_key_get_one_sym(state, code);
|
|
if (kbase != kaltgr) {
|
|
print_sym(kaltgr, qcode, " altgr");
|
|
}
|
|
|
|
xkb_state_update_mask(state, altgr | shift, 0, 0, 0, 0, 0);
|
|
kaltgrshift = xkb_state_key_get_one_sym(state, code);
|
|
if (kshift != kaltgrshift && kaltgr != kaltgrshift) {
|
|
print_sym(kaltgrshift, qcode, " shift altgr");
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void usage(FILE *out)
|
|
{
|
|
fprintf(out,
|
|
"\n"
|
|
"This tool generates qemu reverse keymaps from xkb keymaps,\n"
|
|
"which can be used with the qemu \"-k\" command line switch.\n"
|
|
"\n"
|
|
"usage: qemu-keymap <options>\n"
|
|
"options:\n"
|
|
" -h print this text\n"
|
|
" -f <file> set output file (default: stdout)\n"
|
|
" -m <model> set kbd model (default: %s)\n"
|
|
" -l <layout> set kbd layout (default: %s)\n"
|
|
" -v <variant> set kbd variant (default: %s)\n"
|
|
" -o <options> set kbd options (default: %s)\n"
|
|
"\n",
|
|
names.model, names.layout,
|
|
names.variant ?: "-",
|
|
names.options ?: "-");
|
|
}
|
|
|
|
static xkb_mod_mask_t get_mod(struct xkb_keymap *map, const char *name)
|
|
{
|
|
xkb_mod_index_t mod;
|
|
xkb_mod_mask_t mask = 0;
|
|
|
|
mod = xkb_keymap_mod_get_index(map, name);
|
|
if (mod != XKB_MOD_INVALID) {
|
|
mask = (1 << mod);
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct xkb_context *ctx;
|
|
struct xkb_keymap *map;
|
|
struct xkb_state *state;
|
|
xkb_mod_index_t mod, mods;
|
|
int rc;
|
|
|
|
for (;;) {
|
|
rc = getopt(argc, argv, "hm:l:v:o:f:");
|
|
if (rc == -1) {
|
|
break;
|
|
}
|
|
switch (rc) {
|
|
case 'm':
|
|
names.model = optarg;
|
|
break;
|
|
case 'l':
|
|
names.layout = optarg;
|
|
break;
|
|
case 'v':
|
|
names.variant = optarg;
|
|
break;
|
|
case 'o':
|
|
names.options = optarg;
|
|
break;
|
|
case 'f':
|
|
outfile = fopen(optarg, "w");
|
|
if (outfile == NULL) {
|
|
fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 'h':
|
|
usage(stdout);
|
|
exit(0);
|
|
default:
|
|
usage(stderr);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (outfile == NULL) {
|
|
outfile = stdout;
|
|
}
|
|
|
|
fprintf(outfile,
|
|
"# SPDX-License-Identifier: GPL-2.0-or-later\n"
|
|
"#\n"
|
|
"# generated by qemu-keymap\n"
|
|
"# model : %s\n"
|
|
"# layout : %s\n"
|
|
"# variant : %s\n"
|
|
"# options : %s\n"
|
|
"\n",
|
|
names.model, names.layout,
|
|
names.variant ?: "-",
|
|
names.options ?: "-");
|
|
|
|
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
|
map = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
xkb_context_unref(ctx);
|
|
if (!map) {
|
|
/* libxkbcommon prints error */
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(outfile, "# name: \"%s\"\n\n",
|
|
xkb_keymap_layout_get_name(map, 0));
|
|
fprintf(outfile, "# modifiers\n");
|
|
mods = xkb_keymap_num_mods(map);
|
|
for (mod = 0; mod < mods; mod++) {
|
|
fprintf(outfile, "# %2d: %s\n",
|
|
mod, xkb_keymap_mod_get_name(map, mod));
|
|
}
|
|
|
|
shift = get_mod(map, "Shift");
|
|
ctrl = get_mod(map, "Control");
|
|
altgr = get_mod(map, "AltGr");
|
|
numlock = get_mod(map, "NumLock");
|
|
|
|
state = xkb_state_new(map);
|
|
xkb_keymap_key_for_each(map, walk_map, state);
|
|
xkb_state_unref(state);
|
|
xkb_keymap_unref(map);
|
|
|
|
/* add quirks */
|
|
fprintf(outfile,
|
|
"\n"
|
|
"#\n"
|
|
"# quirks section start\n"
|
|
"#\n"
|
|
"# Sometimes multiple keysyms map to the same keycodes.\n"
|
|
"# The keycode -> keysym lookup finds only one of the\n"
|
|
"# keysyms. So append them here.\n"
|
|
"#\n"
|
|
"\n");
|
|
print_sym(XKB_KEY_Print, Q_KEY_CODE_SYSRQ, "");
|
|
print_sym(XKB_KEY_Sys_Req, Q_KEY_CODE_SYSRQ, "");
|
|
print_sym(XKB_KEY_Execute, Q_KEY_CODE_SYSRQ, "");
|
|
|
|
print_sym(XKB_KEY_KP_Decimal, Q_KEY_CODE_KP_DECIMAL, " numlock");
|
|
print_sym(XKB_KEY_KP_Separator, Q_KEY_CODE_KP_DECIMAL, " numlock");
|
|
|
|
print_sym(XKB_KEY_Alt_R, Q_KEY_CODE_ALT_R, "");
|
|
print_sym(XKB_KEY_ISO_Level3_Shift, Q_KEY_CODE_ALT_R, "");
|
|
print_sym(XKB_KEY_Mode_switch, Q_KEY_CODE_ALT_R, "");
|
|
|
|
fprintf(outfile,
|
|
"\n"
|
|
"# quirks section end\n");
|
|
|
|
exit(0);
|
|
}
|