uinput 是一个内核驱动,应用程序通过它可以在内核中模拟一个输入设备,其设备文件名是 /dev/uinput 或 /dev/input/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 在内核中模拟一个按键输入设备,程序流程如下:
#include
#include
#include
#include
#include
#include
#include
#include
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输入子系统介绍中的按键测试程序