anarkey2.png Gustavo Boiko gave it a name so I threw in a couple of additional code lines to justify the name change. Unlike your previously unnamed hack, which generated only simultaneous key combinations, Anarkey handles sequential keystrokes as well. The configuration file format handles key “chords” like lilypond, so with Anarkey you can use

abc <64 102> 38 56 54

in the configuration file to generate a sequence of fake keystrokes ALT+Right, A, B and C when you run ./ak abc. Build with gcc -o ak ak.c -lXtst, ak.c is listed below. The code is released to the public domain, please refer to the original hack for additional details.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/extensions/XTest.h>

#define CONFFILE "ak.conf"
#define LINE_MAX 256
#define KEY_MAX 100
#define CHORD_ON  (1L << 29)
#define CHORD_OFF (1L << 30)

int main(int argc, char **argv)
{
        FILE *f;
        char *token, line[LINE_MAX];
        int key[KEY_MAX];
        Display *dpy;
        int i, j, keynum;
        int chord, chord_start;

        if (argc != 2)
                fprintf(stderr, "usage: %s \\n”, argv[0]), exit(1);

        if ((f = fopen(CONFFILE, “r”)) == NULL)
                fprintf(stderr, “can’t find configuration file\\n”), exit(1);

        for (; !feof(f); token = NULL) {
                fgets(line, LINE_MAX, f);
                token = strtok(line, ” \\t\\n”);
                if (!strcmp(argv[1], token))
                        break;
        }
        fclose(f);

        if (!token)
                fprintf(stderr, “command %s not defined\\n”, argv[1]), exit(1);

        for (i = 0; i < KEY_MAX; i++) {
                int last;
                if ((token = strtok(NULL, " \\t\\n")) == NULL)
                        break;
                key[i] = 0;
                last = strlen(token) - 1;
                if (*token == '<')
                        token++, key[i] = CHORD_ON;
                if (token[last] == '>‘)
                        token[last] = 0, key[i] = CHORD_OFF;
                key[i] |= strtoul(token, NULL, 0);

        }
        keynum = i;

        if ((dpy = XOpenDisplay(NULL)) == NULL)
                fprintf(stderr, “can’t open display\\n”), exit(1);

        chord = chord_start = 0;
        for (i = 0; i < keynum; i++) {
                if (key[i] & CHORD_ON)
                        chord = 1, chord_start = i, key[i] &= ~CHORD_ON;
                else if (key[i] & CHORD_OFF)
                        chord = -1, key[i] &= ~CHORD_OFF;

                XTestFakeKeyEvent(dpy, key[i], True, CurrentTime);

                if (chord < 0) {
                        for (j = i; j >= chord_start; j-\-)
                                XTestFakeKeyEvent(dpy, key[j], False, CurrentTime);
                        chord = 0;
                } else if (chord == 0)
                        XTestFakeKeyEvent(dpy, key[i], False, CurrentTime);
        }

        XCloseDisplay(dpy);

        return 0;
}

2 Responses to “Improved X11 keystroke injection”

  1. Hell Labs » Quick hack: Simulating X11 keystrokes says:

    [...] a better version is [...]

  2. Jordan Sissel says:

    You might consider looking into xdotool, a project I created a few months ago. It does various event injections (key, mouse, and some window events). It supports keysequences, “type what I tell you to”, and other things.

Leave a Reply