Skip to content
Advertisement

Remap a keyboard with ioctl under linux

I am actually trying to write a small program to catch global keyboard inputs from specific USB keyboards under linux.

I am testing with this piece of code :

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>

static const char *const evval[3] = {
    "RELEASED",
    "PRESSED ",
    "REPEATED"
};

int main(void)
{
    const char *dev = "/dev/input/event2";
    struct input_event ev;
    ssize_t n;
    int fd;
    char name[256]= "Unknown";

//    int codes[2];

//    codes[0] = 58; /* M keycap */
//    codes[1] = 49; /* assign to N */

    fd = open(dev, O_RDONLY);
    if (fd == -1) {
        fprintf(stderr, "Cannot open %s: %s.n", dev, strerror(errno));
        return EXIT_FAILURE;
    }

    if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) 
    {
        printf("The device on %s says its name is '%s'n", dev, name);
    }

    /*
    int err = ioctl(fd, EVIOCSKEYCODE, codes);
    if (err) {
        perror("evdev ioctl");
    }*/

    while (1) {
        n = read(fd, &ev, sizeof ev);
        if (n == (ssize_t)-1) {
            if (errno == EINTR)
                continue;
            else
                break;
        } else
        if (n != sizeof ev) {
            errno = EIO;
            break;
        }

        if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
            printf("%s 0x%04x (%d)n", evval[ev.value], (int)ev.code, (int)ev.code);

    }

    fflush(stdout);
    fprintf(stderr, "%s.n", strerror(errno));

    return EXIT_FAILURE;
}

Ths point is that I don’t know how to change some input key by other. I tried by calling write() on currently red event by changing the event code, sent key was still previous one, and I tried to used ioctl with EVIOCSKEYCODE, but the call failed with an “invalid argument” error (and I’m not sure to call it correctly).

How can I change outputed key correctly ?

Advertisement

Answer

Use the EVIOCGRAB ioctl to grab the input device, so that by reading the events you consume them. Normally (not-grabbed) the events are not consumed when you read them. The ioctl takes an additional parameter, (int)1 for grabbing, (int)0 for releasing.

To re-inject any events, just write them to the uinput device. See eg. a mouse example here. (The event structures are the same type, you only need to write a struct uinput_user_dev structure to the uinput device first, to describe your new input device (which provides the mapped events).)

In other words, you don’t remap: you consume and forward.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement