/* * Loads the XKB keymap from the X11 server and feeds it to xkbcommon. * Necessary so that we can properly let xkbcommon track the keyboard state and * translate keypresses to utf-8. * * Ideally, xkbcommon would ship something like this itself, but as of now * (version 0.2.0), it doesn’t. * */ static bool load_keymap(void) { bool ret = false; XkbFileInfo result; memset(&result, '\0', sizeof(result)); result.xkb = XkbGetKeyboard(display, XkbAllMapComponentsMask, XkbUseCoreKbd); if (result.xkb == NULL) { fprintf(stderr, "[i3lock] XKB: XkbGetKeyboard failed\n"); return false; } FILE *temp = tmpfile(); if (temp == NULL) { fprintf(stderr, "[i3lock] could not create tempfile\n"); return false; } bool ok = XkbWriteXKBKeymap(temp, &result, false, false, NULL, NULL); if (!ok) { fprintf(stderr, "[i3lock] XkbWriteXKBKeymap failed\n"); goto out; } rewind(temp); if (xkb_context == NULL) { if ((xkb_context = xkb_context_new(0)) == NULL) { fprintf(stderr, "[i3lock] could not create xkbcommon context\n"); goto out; } } if (xkb_keymap != NULL) xkb_keymap_unref(xkb_keymap); if ((xkb_keymap = xkb_keymap_new_from_file(xkb_context, temp, XKB_KEYMAP_FORMAT_TEXT_V1, 0)) == NULL) { fprintf(stderr, "[i3lock] xkb_keymap_new_from_file failed\n"); goto out; } struct xkb_state *new_state = xkb_state_new(xkb_keymap); if (new_state == NULL) { fprintf(stderr, "[i3lock] xkb_state_new failed\n"); goto out; } if (xkb_state != NULL) xkb_state_unref(xkb_state); xkb_state = new_state; ret = true; out: XkbFreeKeyboard(result.xkb, XkbAllComponentsMask, true); fclose(temp); return ret; }
int main(void) { struct xkb_context *ctx = test_get_context(0); assert(test_file(ctx, "keymaps/basic.xkb")); assert(test_file(ctx, "keymaps/comprehensive-plus-geom.xkb")); assert(test_file(ctx, "keymaps/no-types.xkb")); assert(test_file(ctx, "keymaps/quartz.xkb")); assert(!test_file(ctx, "keymaps/divide-by-zero.xkb")); assert(!test_file(ctx, "keymaps/bad.xkb")); assert(!test_file(ctx, "keymaps/syntax-error.xkb")); assert(!test_file(ctx, "keymaps/syntax-error2.xkb")); assert(!test_file(ctx, "does not exist")); /* Test response to invalid flags and formats. */ fclose(stdin); assert(!xkb_keymap_new_from_file(ctx, NULL, XKB_KEYMAP_FORMAT_TEXT_V1, 0)); assert(!xkb_keymap_new_from_file(ctx, stdin, 0, 0)); assert(!xkb_keymap_new_from_file(ctx, stdin, XKB_KEYMAP_USE_ORIGINAL_FORMAT, 0)); assert(!xkb_keymap_new_from_file(ctx, stdin, 1234, 0)); assert(!xkb_keymap_new_from_file(ctx, stdin, XKB_KEYMAP_FORMAT_TEXT_V1, -1)); assert(!xkb_keymap_new_from_file(ctx, stdin, XKB_KEYMAP_FORMAT_TEXT_V1, 1234)); xkb_context_unref(ctx); return 0; }
int main(int argc, char *argv[]) { int ret; int opt; struct keyboard *kbds; struct xkb_context *ctx; struct xkb_keymap *keymap; const char *rules = NULL; const char *model = NULL; const char *layout = NULL; const char *variant = NULL; const char *options = NULL; const char *keymap_path = NULL; struct sigaction act; setlocale(LC_ALL, ""); while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:c")) != -1) { switch (opt) { case 'r': rules = optarg; break; case 'm': model = optarg; break; case 'l': layout = optarg; break; case 'v': variant = optarg; break; case 'o': options = optarg; break; case 'k': keymap_path = optarg; break; case 'n': errno = 0; evdev_offset = strtol(optarg, NULL, 10); if (errno) { fprintf(stderr, "error: -n option expects a number\n"); exit(EXIT_FAILURE); } break; case 'c': report_state_changes = true; break; case '?': fprintf(stderr, " Usage: %s [-r <rules>] [-m <model>] " "[-l <layout>] [-v <variant>] [-o <options>]\n", argv[0]); fprintf(stderr, " or: %s -k <path to keymap file>\n", argv[0]); fprintf(stderr, "For both: -n <evdev keycode offset>\n" " -c (to report changes to the state)\n"); exit(EX_USAGE); } } ctx = test_get_context(0); if (!ctx) { ret = -1; fprintf(stderr, "Couldn't create xkb context\n"); goto err_out; } if (keymap_path) { FILE *file = fopen(keymap_path, "r"); if (!file) { ret = EXIT_FAILURE; fprintf(stderr, "Couldn't open '%s': %s\n", keymap_path, strerror(errno)); goto err_ctx; } keymap = xkb_keymap_new_from_file(ctx, file, XKB_KEYMAP_FORMAT_TEXT_V1, 0); fclose(file); } else { keymap = test_compile_rules(ctx, rules, model, layout, variant, options); } if (!keymap) { ret = -1; fprintf(stderr, "Couldn't create xkb keymap\n"); goto err_ctx; } kbds = get_keyboards(keymap); if (!kbds) { ret = -1; goto err_xkb; } act.sa_handler = sigintr_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); /* Instead of fiddling with termios.. */ system("stty -echo"); ret = loop(kbds); if (ret) goto err_stty; err_stty: system("stty echo"); free_keyboards(kbds); err_xkb: xkb_keymap_unref(keymap); err_ctx: xkb_context_unref(ctx); err_out: exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }