我们正在测试创建/关闭 uinput 设备的 C 代码,但遇到了一个奇怪的问题。我们有一个与 uinput 库交互的基本 api:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "uinput_api.h"
int uinput_open() {
int uinput_fd;
uinput_fd = open(UINPUT_DEFAULT_PATH, O_WRONLY | O_NONBLOCK);
return uinput_fd;
}
int uinput_close(int fd) {
if (ioctl(fd, UI_DEV_DESTROY, NULL) == -1) {
printf("ioctl failed and returned errno %s \n", strerror(errno));
close(fd);
return -1;
}
return close(fd);
}
int uinput_enable_event(int uinput_fd, uint16_t event_code) {
if (ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY) == -1) {
return -1;
}
return ioctl(uinput_fd, UI_SET_KEYBIT, event_code);
}
int uinput_create_device(int uinput_fd, struct uinput_setup *usetup) {
if (ioctl(uinput_fd, UI_DEV_SETUP, &usetup) == -1) {
return -1;
}
if (ioctl(uinput_fd, UI_DEV_CREATE) == -1) {
return -1;
}
return 0;
}
int uinput_emit_event(int uinput_fd, uint16_t event_type, uint16_t event_code, int32_t eventvalue) {
struct input_event event;
memset(&event, 0, sizeof(event));
gettimeofday(&event.time, 0);
event.type = event_type;
event.code = event_code;
event.value = eventvalue;
ssize_t bytes;
bytes = write(uinput_fd, &event, sizeof(struct input_event));
if (bytes != sizeof(struct input_event)) {
return -1;
}
return 0;
}
int uinput_emit_event_combo(int uinput_fd, const uint16_t *key_codes, size_t length) {
int retval = 0;
size_t i;
for (i = 0; i < length; ++i) {
if (uinput_emit_event(uinput_fd, EV_KEY, key_codes[i], KEY_PRESSED) == -1) {
retval = -1;
break; /* The combination or the device is
somehow broken: there's no sense to
press any of the rest of the
keys. It's like pressing physical keys
one by one and then discovering that
one of the keys required for this
combination is missing or broken. */
}
}
/* Try to release every pressed key, no matter what. */
while (i--) {
if (uinput_emit_event(uinput_fd, EV_KEY, key_codes[i], KEY_RELEASED) == -1) {
retval = -1;
}
}
return retval;
}
int uinput_emit_syn(int uinput_fd) { return uinput_emit_event(uinput_fd, EV_SYN, SYN_REPORT, KEY_RELEASED); }
当我们单独测试这些功能中的每一个时,它们都可以正常工作。
然后我们编写了一个 api,它应该稍后用作 python 模块:
#include "event_codes.h"
#include "uinput_api.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Externe
// enum for mouvements
enum movements { M_SCROLL_RIGHT, M_SCROLL_LEFT, M_SCROLL_UP, M_SCROLL_DOWN, M_ZOOM_IN, M_ZOOM_OUT };
// init
int init_uinput_device();
// passer le mouvement
int send_movement(int fd, enum movements mouvement_id);
// fermer
int close_uinput_device(int fd);
// interne
int get_movement_value(enum movements mouvement_id);
const int event_tab[] = {SCROLL_UP, SCROLL_DOWN, SCROLL_RIGHT, SCROLL_LEFT, ZOOM_IN, ZOOM_OUT};
int get_movement_value(enum movements mouvement_id) {
switch (mouvement_id) {
case M_SCROLL_RIGHT:
return SCROLL_RIGHT;
case M_SCROLL_LEFT:
return SCROLL_LEFT;
case M_SCROLL_UP:
return SCROLL_UP;
case M_SCROLL_DOWN:
return SCROLL_DOWN;
case M_ZOOM_IN:
return ZOOM_IN;
case M_ZOOM_OUT:
return ZOOM_OUT;
default:
return 0;
}
}
int init_uinput_device() {
int fd = uinput_open();
if (fd == -1) {
printf("init_uinput_device : Error while opening fd\n");
return -1;
}
for (int i = 0; i < NUMBER_OF_EVENTS_HANDLED; ++i) {
int res = uinput_enable_event(fd, event_tab[i]);
if (res == -1) {
printf("init_uinput_device : Error while opening event %d, at position %d\n", event_tab[i], i);
return -1;
}
}
struct uinput_setup usetup;
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_VIRTUAL;
usetup.id.vendor = 0x1234; /* sample vendor */
usetup.id.product = 0x5678; /* sample product */
usetup.id.version = 0x1;
strcpy(usetup.name, "ihm3d_device");
int res = uinput_create_device(fd, &usetup);
if (res == -1) {
printf("init_uinput_device : Error while creating device\n");
return -1;
}
return 0;
}
int send_movement(int fd, enum movements mouvement_id) {
if (uinput_emit_event(fd, EV_KEY, get_movement_value(mouvement_id), KEY_PRESSED) == -1) {
return -1;
}
if (uinput_emit_syn(fd) == -1) {
return -1;
}
if (uinput_emit_event(fd, EV_KEY, get_movement_value(mouvement_id), KEY_RELEASED) == -1) {
return -1;
}
if (uinput_emit_syn(fd) == -1) {
return -1;
}
return 0;
}
int close_uinput_device(int fd) {
if (uinput_close(fd) == -1) {
printf("close_uinput_device : Error while closing fd\n");
return -1;
}
return 0;
}
当我们测试init_uinput_device
andclose_uinput_device
函数时,调用函数时会出错ioctl(fd, UI_DEV_DESTROY, NULL)
。返回的 errno 如下:
Inappropriate ioctl for device
有谁知道错误可能在哪里?
我们已经测试,事件发射部分没有产生错误,唯一的问题是设备的破坏。我们还检查了,设备在 /dev/input 中正确创建
我们正在使用 arm-linux-gnueabihf-gcc 作为编译器在 Rapsberry Pi4 上进行开发