Hash :
cd512b8f
Author :
Date :
2025-05-02T19:21:09
x11: Fix capitalization transformation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/*
* Copyright © 2014 Ran Benita <ran234@gmail.com>
* SPDX-License-Identifier: MIT
*/
#include "config.h"
#include <assert.h>
#include <signal.h>
#include <spawn.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "test.h"
#include "evdev-scancodes.h"
#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-keysyms.h"
#include "xkbcommon/xkbcommon-names.h"
#include "xkbcommon/xkbcommon-x11.h"
#include "xvfb-wrapper.h"
/* Offset between evdev keycodes (where KEY_ESCAPE is 1), and the evdev XKB
* keycode set (where ESC is 9). */
#define EVDEV_OFFSET 8
X11_TEST(test_basic)
{
struct xkb_keymap *keymap = NULL;
struct xkb_state *state = NULL;
xcb_connection_t *conn;
int32_t device_id;
int ret, status;
char *xkb_path;
char *original, *dump;
char *envp[] = { NULL };
char *xkbcomp_argv[] = {
(char *) "xkbcomp", (char *) "-I", NULL /* xkb_path */, display, NULL
};
pid_t xkbcomp_pid;
conn = xcb_connect(display, NULL);
if (xcb_connection_has_error(conn)) {
ret = TEST_SETUP_FAILURE;
goto err_conn;
}
ret = xkb_x11_setup_xkb_extension(conn,
XKB_X11_MIN_MAJOR_XKB_VERSION,
XKB_X11_MIN_MINOR_XKB_VERSION,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
NULL, NULL, NULL, NULL);
if (!ret) {
ret = TEST_SETUP_FAILURE;
goto err_xcb;
}
device_id = xkb_x11_get_core_keyboard_device_id(conn);
assert(device_id != -1);
xkb_path = test_get_path("keymaps/host.xkb");
assert(ret >= 0);
xkbcomp_argv[2] = xkb_path;
ret = posix_spawnp(&xkbcomp_pid, "xkbcomp", NULL, NULL, xkbcomp_argv, envp);
free(xkb_path);
if (ret != 0) {
fprintf(stderr,
"[ERROR] Cannot run xkbcomp. posix_spawnp error %d: %s\n",
ret, strerror(ret));
if (ret == ENOENT) {
fprintf(stderr,
"[ERROR] xkbcomp may be missing. "
"Please install the corresponding package, "
"e.g. \"xkbcomp\" or \"x11-xkb-utils\".\n");
}
ret = TEST_SETUP_FAILURE;
goto err_xcb;
}
ret = waitpid(xkbcomp_pid, &status, 0);
if (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
ret = TEST_SETUP_FAILURE;
goto err_xcb;
}
struct xkb_context *ctx = test_get_context(0);
keymap = xkb_x11_keymap_new_from_device(ctx, conn, device_id,
XKB_KEYMAP_COMPILE_NO_FLAGS);
assert(keymap);
original = test_read_file("keymaps/host.xkb");
assert(original);
dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
assert(dump);
if (!streq(original, dump)) {
fprintf(stderr,
"round-trip test failed: dumped map differs from original\n");
fprintf(stderr, "length: dumped %zu, original %zu\n",
strlen(dump),
strlen(original));
fprintf(stderr, "dumped map:\n");
fprintf(stderr, "%s\n", dump);
ret = 1;
goto err_dump;
}
state = xkb_x11_state_new_from_device(keymap, conn, device_id);
assert(state);
/* Check capitalization transformation */
xkb_keysym_t sym;
sym = xkb_state_key_get_one_sym(state, KEY_A + EVDEV_OFFSET);
assert(sym == XKB_KEY_a);
sym = xkb_state_key_get_one_sym(state, KEY_LEFT + EVDEV_OFFSET);
assert(sym == XKB_KEY_Left);
const xkb_mod_index_t caps_idx =
xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
assert(caps_idx != XKB_MOD_INVALID);
const xkb_mod_mask_t caps = UINT32_C(1) << caps_idx;
xkb_state_update_mask(state, 0, 0, caps, 0, 0, 0);
sym = xkb_state_key_get_one_sym(state, KEY_A + EVDEV_OFFSET);
assert(sym == XKB_KEY_A);
sym = xkb_state_key_get_one_sym(state, KEY_LEFT + EVDEV_OFFSET);
assert(sym == XKB_KEY_Left);
ret = EXIT_SUCCESS;
err_dump:
free(original);
free(dump);
xkb_state_unref(state);
xkb_keymap_unref(keymap);
xkb_context_unref(ctx);
err_xcb:
xcb_disconnect(conn);
err_conn:
return ret;
}
int main(void) {
test_init();
return x11_tests_run();
}