Example #1
0
/*
 * 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;
}
Example #2
0
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;
}
Example #3
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);
}