使用 uinput 在 Linux 中模拟绝对鼠标移动
我正在尝试使用绝对坐标移动光标。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <signal.h>
#define die(str, args...) do { \
perror(str); \
exit(EXIT_FAILURE); \
} while(0)
int fd;
static void signal_handler(int signo)
{
printf("\nCaught SIGINT\n");
if(ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: cannot destroy uinput device\n");
else printf("Destroyed uinput_user_dev\n\n");
close(fd);
exit(EXIT_SUCCESS);
}
int
main(void)
{
struct uinput_user_dev uidev;
struct input_event ev;
int x, y;
int i;
if(signal(SIGINT,signal_handler)==SIG_ERR)
{
printf("error registering signal handler\n");
exit(EXIT_FAILURE);
}
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd < 0)
die("error: open");
if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
die("error: ioctl");
// if(ioctl(fd, UI_SET_KEYBIT, BTN_MOUSE) < 0)
// die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_REL) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_Y) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_ABSBIT,ABS_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0)
die("error: ioctl");
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
uidev.absmin[ABS_X]=0;
uidev.absmax[ABS_X]=1023;
uidev.absfuzz[ABS_X]=0;
uidev.absflat[ABS_X ]=0;
uidev.absmin[ABS_Y]=0;
uidev.absmax[ABS_Y]=767;
uidev.absfuzz[ABS_Y]=0;
uidev.absflat[ABS_Y ]=0;
if(write(fd, &uidev, sizeof(uidev)) < 0)
die("error: write0");
if(ioctl(fd, UI_DEV_CREATE) < 0)
die("error: ioctl");
sleep(2);
while(1)
{
printf("\nEnter the absoulte x(0-1023) and y(0-767) co-ordinates:");
scanf("%d %d",&x,&y);·······
memset(&ev, 0, sizeof(struct input_event));
gettimeofday(&ev.time,NULL);
ev.type = EV_ABS;
ev.code = ABS_X;
ev.value = x;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write1");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write4");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_ABS;
ev.code = ABS_Y;
ev.value = y;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write2");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write3");
usleep(15000);
printf("\nWritten x:%d y:%d to uinput.Press CTRL-C to quit:",x,y);
}
if(ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: cannot destroy uinput device\n");
close(fd);
return 0;
}
该程序似乎通过 uinput 将我输入的绝对坐标发送到内核的输入核心。
启用 evbug 后我在 dmesg 上验证了这一点。但我的鼠标指针在屏幕上无法移动。我在想我搞砸了什么。
也许 EV_ABS 没有与光标绑定?我想知道因为使用 EV_REL 工作正常,如 本教程。
示例运行:
ravi@linux-lxaf:~/workspace/driver> sudo ./a.out
Enter the absoulte x(0-1023) and y(0-767) co-ordinates:100 200
Written x:100 y:200 to uinput.Press CTRL-C to quit:
Enter the absoulte x(0-1023) and y(0-767) co-ordinates:10 765
Written x:10 y:765 to uinput.Press CTRL-C to quit:
Enter the absoulte x(0-1023) and y(0-767) co-ordinates:^C
Caught SIGINT
Destroyed uinput_user_dev
Dmesg 输出:
ravi@linux-lxaf:~/workspace/driver> dmesg |grep input16
[ 4750.660420] input: uinput-sample as /devices/virtual/input/input16
[ 4750.660594] evbug.c: Connected device: input16 (uinput-sample at unknown)
[ 4761.389036] evbug.c: Event. Dev: input16, Type: 3, Code: 0, Value: 100
[ 4761.389047] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4761.389053] evbug.c: Event. Dev: input16, Type: 3, Code: 1, Value: 200
[ 4761.389058] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4776.893126] evbug.c: Event. Dev: input16, Type: 3, Code: 0, Value: 10
[ 4776.893138] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4776.893144] evbug.c: Event. Dev: input16, Type: 3, Code: 1, Value: 765
[ 4776.893148] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4778.729711] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 1
[ 4778.745506] evbug.c: Disconnected device: input16
I'm trying to move the cursor around using absolute co-ordinates. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <signal.h>
#define die(str, args...) do { \
perror(str); \
exit(EXIT_FAILURE); \
} while(0)
int fd;
static void signal_handler(int signo)
{
printf("\nCaught SIGINT\n");
if(ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: cannot destroy uinput device\n");
else printf("Destroyed uinput_user_dev\n\n");
close(fd);
exit(EXIT_SUCCESS);
}
int
main(void)
{
struct uinput_user_dev uidev;
struct input_event ev;
int x, y;
int i;
if(signal(SIGINT,signal_handler)==SIG_ERR)
{
printf("error registering signal handler\n");
exit(EXIT_FAILURE);
}
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd < 0)
die("error: open");
if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
die("error: ioctl");
// if(ioctl(fd, UI_SET_KEYBIT, BTN_MOUSE) < 0)
// die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_REL) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_Y) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_ABSBIT,ABS_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0)
die("error: ioctl");
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
uidev.absmin[ABS_X]=0;
uidev.absmax[ABS_X]=1023;
uidev.absfuzz[ABS_X]=0;
uidev.absflat[ABS_X ]=0;
uidev.absmin[ABS_Y]=0;
uidev.absmax[ABS_Y]=767;
uidev.absfuzz[ABS_Y]=0;
uidev.absflat[ABS_Y ]=0;
if(write(fd, &uidev, sizeof(uidev)) < 0)
die("error: write0");
if(ioctl(fd, UI_DEV_CREATE) < 0)
die("error: ioctl");
sleep(2);
while(1)
{
printf("\nEnter the absoulte x(0-1023) and y(0-767) co-ordinates:");
scanf("%d %d",&x,&y);·······
memset(&ev, 0, sizeof(struct input_event));
gettimeofday(&ev.time,NULL);
ev.type = EV_ABS;
ev.code = ABS_X;
ev.value = x;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write1");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write4");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_ABS;
ev.code = ABS_Y;
ev.value = y;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write2");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write3");
usleep(15000);
printf("\nWritten x:%d y:%d to uinput.Press CTRL-C to quit:",x,y);
}
if(ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: cannot destroy uinput device\n");
close(fd);
return 0;
}
The program seems to send the absolute co-ordinates that I type to the kernel's input core via uinput.
I verified this on dmesg after enabling evbug. But my mouse pointer won't move on the screen. I'm wondering what I'm messing up.
Perhaps EV_ABS is not tied to the cursor? I wonder because moving the cursor using EV_REL works fine as mentioned in this tutorial.
Sample run:
ravi@linux-lxaf:~/workspace/driver> sudo ./a.out
Enter the absoulte x(0-1023) and y(0-767) co-ordinates:100 200
Written x:100 y:200 to uinput.Press CTRL-C to quit:
Enter the absoulte x(0-1023) and y(0-767) co-ordinates:10 765
Written x:10 y:765 to uinput.Press CTRL-C to quit:
Enter the absoulte x(0-1023) and y(0-767) co-ordinates:^C
Caught SIGINT
Destroyed uinput_user_dev
Dmesg output:
ravi@linux-lxaf:~/workspace/driver> dmesg |grep input16
[ 4750.660420] input: uinput-sample as /devices/virtual/input/input16
[ 4750.660594] evbug.c: Connected device: input16 (uinput-sample at unknown)
[ 4761.389036] evbug.c: Event. Dev: input16, Type: 3, Code: 0, Value: 100
[ 4761.389047] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4761.389053] evbug.c: Event. Dev: input16, Type: 3, Code: 1, Value: 200
[ 4761.389058] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4776.893126] evbug.c: Event. Dev: input16, Type: 3, Code: 0, Value: 10
[ 4776.893138] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4776.893144] evbug.c: Event. Dev: input16, Type: 3, Code: 1, Value: 765
[ 4776.893148] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 0
[ 4778.729711] evbug.c: Event. Dev: input16, Type: 0, Code: 0, Value: 1
[ 4778.745506] evbug.c: Disconnected device: input16
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我刚刚发现输入核心将 EV_ABS 值作为绝对值传播到设备节点,正如通过读取 /dev/input/eventX 发现的那样(现在看起来很明显!)。一直以来,控制光标(X11?)的应用程序期望相对鼠标移动,而我给它绝对值,这可能会混淆它!
I just found out that the input core propagates the EV_ABS values as absolute values to the device node, as found out from reading /dev/input/eventX (Seems so obvious now !).All along, the application controlling the cursor (X11?) was expecting relative mouse moves while I was giving it absolute values, which probably confused it!