Simulating absolute mouse movements in Linux using uinput

10,555

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!

Share:
10,555
itisravi
Author by

itisravi

EE/CS dude, GlusterFS developer, Amateur road biker etc.

Updated on June 05, 2022

Comments

  • itisravi
    itisravi almost 2 years

    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
    
  • Asain Kujovic
    Asain Kujovic about 9 years
    hey, i have same problem as your question, can you explain better what is your conclusions please. can uinput device be REL and ABS for example... GDM is ok with that but X not. is there a link where you find out usefull things about this
  • Alex
    Alex over 8 years
    @AsainKujovic see doc/Documentation/input/event-codes.txt much more clear, ABS are events like touch screen tap, probably (have to check) X on mice listen for REL only (how could a mouse send an abs event if it doesn't know the screen resolution)
  • S.I.J
    S.I.J over 8 years
    @Alex I have my touch working but can't figure out how to generate click events. Can you please tell me how should I do that.
  • Alex
    Alex over 8 years
    @ShaheenIquebal I can't tell but here's some old link which hopefully may help you, old stuff but should still work: input26/udpmouse docs input, input26 (Italian)
  • S.I.J
    S.I.J over 8 years
    @Alex Thanks, will have a look