Конвертировать Char в код ключа ядра (для использования при входе)

Я пытаюсь сделать виртуальную клавиатуру с помощью uinput на Debian Stretch, чтобы я мог кормить ее строками, такими как "Toto!", И клавиатура могла бы написать эту строку. Тем не менее, я застрял с преобразованием из C char в коды клавиш, которые обрабатываются с помощью клавиатуры. Я не использую макросы, определенные в event-codes.h, потому что я хочу, чтобы мое решение работало на локали компьютера, а макросы определяются на американской клавиатуре.

Вот устройство, созданное с помощью uinput:

int setup_uinput_device(){
/* Temporary variable */
    int i=0;
/* Open the input device */
    uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
    if (fcntl(uinp_fd, F_GETFD) == -1)
    {
        printf("Unable to open /dev/uinput\n");
        return -1;
    }
    memset(&uinp,0,sizeof(uinp)); /* Intialize the uInput device to NULL */
    strncpy(uinp.name, "Custom Keyboard", UINPUT_MAX_NAME_SIZE);
    uinp.id.bustype = BUS_USB;
    // Setup the uinput device
    ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
    ioctl(uinp_fd, UI_SET_EVBIT, EV_REL);
    ioctl(uinp_fd, UI_SET_EVBIT, EV_REP);
    for (i=0; i < 256; i++) {
        ioctl(uinp_fd, UI_SET_KEYBIT, i);
    }
    /* Create input device into input sub-system */
    write(uinp_fd, &uinp, sizeof(uinp));
    if (ioctl(uinp_fd, UI_DEV_CREATE))
    {
        printf("Unable to create UINPUT device.\n");
        return -1;
    }
    return 0;
}

Я уже пробовал решения с использованием библиотеки X11, как показано в этой ссылке: Преобразование символа ASCII в код ключа x11. К сожалению, клавиатура, которую мне удалось создать с помощью uinput, использует разные коды клавиш, чем те, которые использует X11. (Я думаю, что моя клавиатура использует те же коды клавиш, которые можно получить с помощью команды dumpkeys). Конечно, возможно преобразовать коды клавиш X11 в (ядро?) Коды клавиш, которые правильно интерпретирует моя клавиатура, но я бы хотел, чтобы количество зависимостей было низким.

Сейчас я пытаюсь использовать EVIOCGKEYCODE, как показано в linux.h, но мне трудно понять, как это работает, и я думаю, что это противоположно тому, что я действительно хочу.

Вот пример:

int main(int argc, char *argv[]) {
    setup_uinput_device();
    struct input_keymap_entry mapping;
    int i =0;
    /* Set the max value at 130 just for the purpose of testing */    
    for (i=0; i<130; i++) {
        mapping.scancode[0] = i;
        if(ioctl(fd, EVIOCGKEYCODE_V2, mapping)) {
            perror("evdev ioctl");
        }
        printf("Scancode= %d, Keycode = %d\n",
               mapping.scancode[0], mapping.keycode);
    }
    /* Simple function to destroy the device */
    destroy_uinput_device();
    return 0;
} 

Я получаю следующую ошибку: "evdev ioctl: Неверный аргумент". Я где-то читал, что это старый метод, используемый с клавиатурой PS2, поэтому, вероятно, это одна из многих причин, по которой он не работает.

Последнее решение, которое я рассмотрю, - это проанализировать результат дампа в таблице или на карте, которые я мог бы использовать позже, но я думаю, что у меня возникнут проблемы с производительностью, и я не хочу воссоздавать то, что, возможно, уже существует.

Любая идея?

1 ответ

Решение

Так что после долгих попыток я наконец понял, что код ядра, используемый ядром, тот же, что и код X11 минус 8.

Сначала я должен был управлять кодированием. Я использовал следующий код для управления многобайтовыми символами (например, €):

    char *str = "Test €";
    size_t mbslen; /* Number of multibyte characters in source */
    wchar_t *wcs; /* Pointer to converted wide character string */
    wchar_t *wp;
    setlocale(LC_ALL, "");

    mbslen = mbstowcs(NULL, str, 0);
    if (mbslen == (size_t) -1) {
            perror("mbstowcs");
            exit(ERROR_FAILURE);
    }

    wcs = calloc(mbslen + 1, sizeof(wchar_t));
    if (wcs == NULL) {
            perror("calloc");
            exit(ERROR_FAILURE);
    }

    /* Convert the multibyte character string in str to a wide character string */
    if (mbstowcs(wcs, str, mbslen + 1) == (size_t) -1) {
            perror("mbstowcs");
            exit(ERROR_FAILURE);
    }

Затем, используя эту таблицу преобразования из ucs в keysym, мне удалось преобразовать массив widechar в соответствующие ему последовательности Keycode, основываясь на примере, который я привел в своем первоначальном вопросе.

Последний шаг состоял в том, чтобы подать на мою клавиатуру ввода код X11 с кодом минус 8.

Другие вопросы по тегам