在linux2.6.x内核使用uinput驱动实现用户输入响应

linux2.6.x内核提供了uinput驱动,它可以帮助用户将数据(包括用户输入的键盘或者鼠标或者触摸板数据)注入到Linux内核,这对于编写用户自定义的输入设备的应用程序是非常有用的。

驱动程序使用/ dev/ uinput的设备,将数据发送到内核空间,而内核反过来将数据发送到X-Windows或者shell终端。此功能可用于所有涉及的图形用户输入。

uinput驱动在许多linux内核里均被配置为可加载的模块,你可以通过如下的命令加载luinput驱动。

$ modprobe uinput

$ lsmod

lsmod”命令列出了linux系统已经加载的所有驱动。你应该可以看到“uinput”驱动也在这个列表中。但是如果你是在kernel里把uinput设置成编译进内核,而不是编译成模块的话,那么你通过lsmod是看不到uinput模块的。但你在/dev下会看到uinput的设备结点。后面你可以直接打开此结点来向uinput发送数据。

接下来我们开发一个简单的应用程序,该应用程序将发送键值到kernel,而kernel将键值发送到x-windowshell终端。

1:打开uinput设备:

Uinp_fd = open(/dev/uinput,O_WRONLY|O_NDELAY);

If(uinp_fd == NULL)

{

printf(unable to open /dev/uinput\n);

Return -1;

}

成功打开设备之后,需要通过驱动的ioctl函数来配置uinput设备的参数,包括鼠标参数、键盘参数等。如下:

ioctl(out_fd,UI_SET_EVBIT,EV_KEY);

ioctl(out_fd,UI_SET_EVBIT,EV_REP);

EV_KEYEV_REP来告诉uinput驱动是包含键值的键盘事件。

所有来自用户进程的事件都会通过结构体“struct input_event”(在/usr/include/linux/input.h中定义)传送给内核空间。

可以通过下面的代码产生键盘事件:

event.type = EV_KEY;

event.code = KEY_ENTER;

event.value = 1;

write(uinp_fd,&event,sizeof(event));

__u16 type; //类型,在下面有定义
__u16 code; //要模拟成什么按键
__s32 value;//是按下还是释放

上面的代码将要发送一个enter键给内核。该键值最终会通过内核发送给用户空间的应用程序。所有的按键定义在“/usr/include/linux/input.h”中;

你可以通过下面的例子去测试linux uinput的接口:

// uinput.c

#include <string.h>

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <linux/input.h>

#include <linux/uinput.h>

#include <stdio.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

/* Globals */

static int uinp_fd = -1;

struct uinput_user_dev uinp;

// uInput device structure

struct input_event event; // Input device structure

/* Setup the uinput device */

int setup_uinput_device()

{

// Temporary variable

int i=0;

// Open the input device

uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);

if (uinp_fd == NULL)

{

}

printf("Unable to open /dev/uinput\n");

return -1;

memset(&uinp,0,sizeof(uinp)); // Intialize the uInput device to NULL

strncpy(uinp.name, "PolyVision Touch Screen", UINPUT_MAX_NAME_SIZE);

uinp.id.version = 4;

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_RELBIT, REL_X);

ioctl(uinp_fd, UI_SET_RELBIT, REL_Y);

for (i=0; i < 256; i++) {

ioctl(uinp_fd, UI_SET_KEYBIT, i);

}

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_TOUCH);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_LEFT);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MIDDLE);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_RIGHT);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_FORWARD);

ioctl(uinp_fd, UI_SET_KEYBIT, BTN_BACK);

/* 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.");

return -1;

}

return 1;

void send_click_events( )

{

// Move pointer to (0,0) location

memset(&event, 0, sizeof(event));

gettimeofday(&event.time, NULL);

event.type = EV_REL;

event.code = REL_X;

event.value = 100;

write(uinp_fd, &event, sizeof(event));

event.type = EV_REL;

event.code = REL_Y;

event.value = 100;

write(uinp_fd, &event, sizeof(event));

event.type = EV_SYN;

event.code = SYN_REPORT;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

// Report BUTTON CLICK - PRESS event

memset(&event, 0, sizeof(event));

gettimeofday(&event.time, NULL);

event.type = EV_KEY;

event.code = BTN_LEFT;

event.value = 1;

write(uinp_fd, &event, sizeof(event));

event.type = EV_SYN;

event.code = SYN_REPORT;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

// Report BUTTON CLICK - RELEASE event

memset(&event, 0, sizeof(event));

gettimeofday(&event.time, NULL);

event.type = EV_KEY;

event.code = BTN_LEFT;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

}

event.type = EV_SYN;

event.code = SYN_REPORT;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

void send_a_button()

{

// Report BUTTON CLICK - PRESS event

memset(&event, 0, sizeof(event));

gettimeofday(&event.time, NULL);

event.type = EV_KEY;

event.code = KEY_A;

event.value = 1;

write(uinp_fd, &event, sizeof(event));

event.type = EV_SYN;

event.code = SYN_REPORT;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

// Report BUTTON CLICK - RELEASE event

memset(&event, 0, sizeof(event));

gettimeofday(&event.time, NULL);

event.type = EV_KEY;

event.code = KEY_A;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

}

event.type = EV_SYN;

event.code = SYN_REPORT;

event.value = 0;

write(uinp_fd, &event, sizeof(event));

/* This function will open the uInput device. Please make

sure that you have inserted the uinput.ko into kernel. */

int main()

{

// Return an error if device not found.

if (setup_uinput_device() < 0)

{

printf("Unable to find uinput device\n");

return -1;

}

send_a_button(); // Send a "A" key

send_click_events(); // Send mouse event

/* Destroy the input device */

ioctl(uinp_fd, UI_DEV_DESTROY);

}

/* Close the UINPUT device */

close(uinp_fd);



//在我们的项目中我们做了一个android悬浮控制,上层java实现用户交互,在接收到虚拟的按键后,调用通过jni封装得uinput 模块,最终通过uinput模块将按键发送给kernel。通过jni将c实现的与uinput通信的模块封装成so,在android上层apk调用so,实现虚拟按键的触发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值