在Linux中使用uinput模拟绝对鼠标移动

9

我正在尝试使用绝对坐标移动光标。下面是代码:

#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移动光标在this tutorial中提到的很好。 示例运行:
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

小小的旁注。这段代码不仅适用于X窗口系统,也可以在Wayland上正常运行。 - pktiuk
1个回答

5

我刚刚发现输入核心将EV_ABS值作为绝对值传播到设备节点,从读取/dev/input/eventX中发现(现在看来似乎很明显!)。一直以来,控制光标的应用程序(X11?)都期望相对鼠标移动,而我却给它绝对值,这可能让它感到困惑!


3
嘿,我和你的问题一样,你能更好地解释一下你的结论吗?例如,输入设备可以是REL和ABS吗?GDM可以,但X不行。你有找到有用信息的链接吗? - Asain Kujovic
@AsainKujovic 请查看doc/Documentation/input/event-codes.txt,更加清晰明了。ABS是像触摸屏轻击这样的事件,可能(需要检查)鼠标上的X仅监听REL事件(如果它不知道屏幕分辨率,那么鼠标如何发送ABS事件)。 - Alex
@Alex,我的触摸功能已经可以使用了,但是我不知道如何生成点击事件。你能告诉我应该怎么做吗? - S.I.J
@Alex 谢谢,我会查看的。 - S.I.J
我在这里执行你的代码时遇到了同样的问题,我能够输入x和y坐标,但鼠标指针没有任何反应... 你能让这段代码运行吗? - theEarlyRiser
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接