uinput 简介
uinput 是一个内核驱动,应用程序通过它可以在内核中模拟一个输入设备,其设备文件名是 /dev/uinput 或 /dev/input/uinput。
uinput 使用
使用 uinput 时遵循以下步骤:
- 通过 open 打开 uinput 设备
- 通过 ioctl 设置属性位图
- 通过 ioctl 设置事件类型位图和对应的事件码位图
- 通过 ioctl 设置ID和名称
- 通过 ioctl 创建输入设备
- 通过 write 上报输入事件
- 通过 close 关闭 uinput 设备
使能 uinput
在内核源码目录通过 make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- menuconfig 打开配置菜单,然后选择 User level driver support ,路径如下:
-> Device Drivers-> Input device support-> Miscellaneous devices<M> User level driver support
如果选择编译成模块,其生成 ko 文件位于内核目录的 drivers/input/misc/中,文件名是uinput.ko
编程实践
在应用层中使用 uinput 在内核中模拟一个按键输入设备,程序流程如下:
- 打开 uinput 设备
- 设置属性位图、事件类型位图、事件码位图
- 设置ID和名称
- 创建输入设备
- 周期上报按键事件
完整的代码如下所示:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/uinput.h>void emit(int fd, int type, int code, int val)
{struct input_event ie;ie.type = type;ie.code = code;ie.value = val;//以下参数忽略ie.time.tv_sec = 0;ie.time.tv_usec = 0;//上报输入事件write(fd, &ie, sizeof(ie));
}int main(int argc, const char *argv[])
{int fd;struct uinput_setup usetup;const char *name = "/dev/uinput";if(argc >= 2)name = argv[1];//打开 uinput 设备fd = open(name, O_WRONLY);if(fd < 0){perror("open");return -1;}//设置属性位图if(ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_BUTTONPAD) < 0){close(fd);perror("UI_SET_PROPBIT");return -1;}//设置事件类型位图和对应的事件码位图if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0){close(fd);perror("UI_SET_EVBIT");return -1;}if(ioctl(fd, UI_SET_KEYBIT, KEY_0) < 0){close(fd);perror("UI_SET_KEYBIT");return -1;}//设置ID和名称memset(&usetup, 0, sizeof(usetup));usetup.id.bustype = BUS_USB;usetup.id.vendor = 0x1234;usetup.id.product = 0x5678;strcpy(usetup.name, "Example device");if(ioctl(fd, UI_DEV_SETUP, &usetup) < 0){close(fd);perror("UI_DEV_SETUP");return -1;}//创建输入设备if(ioctl(fd, UI_DEV_CREATE) < 0){close(fd);perror("UI_DEV_CREATE");return -1;}while(1){emit(fd, EV_KEY, KEY_0, 1);emit(fd, EV_SYN, SYN_REPORT, 0);usleep(500*1000);emit(fd, EV_KEY, KEY_0, 0);emit(fd, EV_SYN, SYN_REPORT, 0);usleep(500*1000);}//close(fd);
}
测试程序参考10.1Linux输入子系统介绍中的按键测试程序
上机测试
- 修改内核,使能 uinput
- 在这里下载代码,并进行编译,得到 uinput_app.out 和 test_app.out 两个可执行程序。
- 执行命令 ./uinput_app.out ,此时会通过 uinput 在内核空间创建一个按键输入设备。
- 打开另一个终端,执行命令 ./test_app.out /dev/input/event0 ,运行测试程序,其中 /dev/input/event0 为按键输入设备的文件名,由系统自动生成,需要根据实际情况确定,此时测试程序会输出按键状态。