Linux下鼠标信息读取

2013年5月14日 由 Creater 留言 »

1. 关于”/dev/input/mice”
相信很多人都用过Linux,也许你发现不管是在X-window下面,还是在Console下面,鼠标都是可以操作的。那么你有没有考虑过这些鼠标都是从哪来的?

不错!他们都是从”/dev/input/mice”这个文件里来的。如果你对Linux比较熟,那么你肯定看得出来这是一个设备文件。”mice”就是Linux下面鼠标的设备文件,不管你用的是PS2的还是USB的,所有关于鼠标的操作都被抽象到”mice”这个文件中。

2. “mice”之母
在linux下面,她是”mousedev.c”这个文件。你可以在内核的”Drivers/input”目录里找到她。在她那里,你可以得到关于”mice”的一切。

3. 坐标
如何得到mouse的当前坐标值?可通过如下几步:

1)打开”/dev/input/mice”文件。

2)读3个字节。三个字节的值分别是“Button类型”,“X的相对位移”,“Y的相对位移”。这里先用Button, xRel, yRel表示。

3)取Button的低3位(Button & 0x07)。0x00 = LeftButtonUp, 0x01 = LeftButtonDown, 0x02 = RightButtonDown.

4)因为这里取得是相对位移,所以X, Y要分别与上一次的坐标值相加。xPos += xRel; yPos +=yRel.

好了,到这里完成了一次读取操作。具体的代码请参见附录一。附录二介绍一下gpm。

我很奇怪为什么在网上找不到这方面的资料,关于gpm的资料也是寥寥无几。

#include <stdio.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main (int argc, char **argv)
{
    int fd, retval;
    char buf[6];
    fd_set readfds;
    struct timeval tv;
    fd = open ("/dev/input/mice", O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        printf ("Failed to open /dev/input/mice /n");
        return -1;
    }
    printf ("Suceed to open /dev/input/mice.fd = %d/n", fd);
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    while (1) {
        FD_ZERO (&readfds);
        FD_SET (fd, &readfds);
        retval = select (fd + 1, &readfds, NULL, NULL, &tv);
        printf ("retval = %d/n", retval);
        if (retval == 1) {
            printf ("select OK. /n");
            if (read (fd, buf, 6) <= 0) {
                printf ("Fail to read. /n");
                continue;
            }
            printf ("Button type = %d, X = %d, Y = %d./n",
                    buf[0] & 0x07, buf[1], buf[2]);
        }
    }
    close (fd);
    return 0;
}

附录二:
gpm是linux console下的鼠标操作服务。用它可以实现copy和paste操作。你也可以用gpm提供的API得到鼠标的坐标。但这些API的原理也是跟上面讲的一样,都是操作mice文件。

    #include <stdio.h>  
    #include <errno.h>  
    #include <fcntl.h>  
    #include <sys/select.h>  
    #include <string.h>  
      
    /* Mouse button bits*/  
    #define WHEEL_UP 0x10  
    #define WHEEL_DOWN 0x08  
      
    #define BUTTON_L 0x04  
    #define BUTTON_M 0x02  
    #define BUTTON_R 0x01  
    #define SCALE 3 /* default scaling factor for acceleration */  
    #define THRESH 5 /* default threshhold for acceleration */  
      
    static int xpos; /* current x position of mouse */  
    static int ypos; /* current y position of mouse */  
    static int minx; /* minimum allowed x position */  
    static int maxx; /* maximum allowed x position */  
    static int miny; /* minimum allowed y position */  
    static int maxy; /* maximum allowed y position */  
    static int buttons; /* current state of buttons */  
    static int scale = SCALE; /* acceleration scale factor */  
    static int thresh = THRESH;/* acceleration threshhold */  
      
    static int mouse_update(int dx, int dy, int dz);  
    static int IMPS2_Read (int *dx, int *dy, int *dz, int *bp);  
    static void mouse_setposition (int newx, int newy);  
    static void mouse_setrange (int newminx, int newminy, int newmaxx, int newmaxy);  
      
    int mouse_fd;  
      
    int main(void)  
    {  
        int dx,dy,dz;  
        static unsigned char imps2_param [] = {243,200,243,100,243,80};//,242};  
        // 来自vnc4的xc/programs/Xserver/hw/xfree86/input/mouse/mouse.c==>PROT_IMPS2  
        const char *mdev="/dev/input/mice";  
      
         mouse_fd = open (mdev, O_RDWR); // | O_NONBLOCK);  
        if (mouse_fd < 0) {  
            printf("[luther.gliethttp]: RW error [please use root user]: %s\n", mdev);  
             mouse_fd = open (mdev, O_RDONLY); // | O_NONBLOCK);  
            if (mouse_fd < 0)  
                return -1;  
        } else {  
            write (mouse_fd, imps2_param, sizeof (imps2_param)); // 初始化序列, 这样可以读取4个字节数据  
            // 0x80用来表示滚轮向上还是向下滚动.de>  
      
            // 0xa0表示滚轮向上滚动的同时中键按下  
             printf("[luther.gliethttp]: imps2_param ok!\n");  
        }  
          
         mouse_setrange(0, 0, 1024, 768);  
      
        for (;;) {  
             IMPS2_Read(&dx, &dy, &dz, &buttons);  
             mouse_update(dx, dy, dz);  
             mouse_setposition(xpos, ypos);  
            printf("[%04d,%04d,0x%04x]\n", xpos, ypos, buttons);  
        }  
          
        return 0;  
    }  
      
    static int IMPS2_Read (int *dx, int *dy, int *dz, int *bp)  
    {  
        static unsigned char buf[5];  
        static int buttons[7] = { 0, 1, 3, 0, 2, 0, 0}; // 1左键,2中键,3右键  
        static int nbytes;  
        int n;  
      
        while ((n = read (mouse_fd, &buf [nbytes], 4 - nbytes))) {  
            if (n < 0) {  
                if (errno == EINTR)  
                    continue;  
                else  
                    return -1;  
            }  
      
             nbytes += n;  
      
            if (nbytes == 4) {  
                int wheel;  
                // printf("[luther.gliethttp]: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);  
                if ((buf[0] & 0xc0) != 0) {  
                     buf[0] = buf[1];  
                     buf[1] = buf[2];  
                     buf[2] = buf[3];  
                     nbytes = 3;  
      
                    return -1;  
                }  
      
                /* FORM XFree86 4.0.1 */  
                *bp = buttons[(buf[0] & 0x07)];  
                *dx = (buf[0] & 0x10) ? buf[1] - 256 : buf[1];  
                *dy = (buf[0] & 0x20) ? -(buf[2] - 256) : -buf[2];  
      
                /* Is a wheel event? */  
                if ((wheel = buf[3]) != 0) {  
                    if(wheel > 0x7f) {  
                        *bp |= WHEEL_UP;  
                    }  
                    else {  
                        *bp |= WHEEL_DOWN;  
                    }  
                }  
                   
                *dz = 0;  
                 nbytes = 0;  
                return 1;  
            }  
        }  
        return 0;  
    }  
      
    static int mouse_update(int dx, int dy, int dz)  
    {  
        int r;  
        int sign;  
          
         sign = 1;  
        if (dx < 0) {  
             sign = -1;  
             dx = -dx;  
        }  
        if (dx > thresh)  
             dx = thresh + (dx - thresh) * scale;  
         dx *= sign;  
         xpos += dx;  
        if( xpos < minx )  
             xpos = minx;  
        if( xpos > maxx )  
             xpos = maxx;  
      
         sign = 1;  
        if (dy < 0) {  
             sign = -1;  
             dy = -dy;  
        }  
        if (dy > thresh)  
             dy = thresh + (dy - thresh) * scale;  
         dy *= sign;  
         ypos += dy;  
        if ( ypos < miny )  
             ypos = miny;  
        if ( ypos > maxy )  
             ypos = maxy;  
      
        return 1;  
    }  
      
    static void mouse_setposition (int newx, int newy)  
    {  
        if (newx < minx)  
             newx = minx;  
        if (newx > maxx)  
             newx = maxx;  
        if (newy < miny)  
             newy = miny;  
        if (newy > maxy)  
             newy = maxy;  
        if (newx == xpos && newy == ypos)  
            return;  
         xpos = newx;  
         ypos = newy;  
    }  
      
    static void mouse_setrange (int newminx, int newminy, int newmaxx, int newmaxy)  
    {  
         minx = newminx;  
         miny = newminy;  
         maxx = newmaxx;  
         maxy = newmaxy;  
         mouse_setposition ((newminx + newmaxx) / 2, (newminy + newmaxy) / 2);  
    }  
      
    static int mouse_getbutton (void)  
    {  
        return buttons;  
    }  
      
    static void mouse_getxy (int* x, int* y)  
    {  
        *x = xpos;  
        *y = ypos;  
    }  

用C语言在Linux下获取鼠标光标的相对位置代码分享:

    #include <stdio.h>   
    #include <stdlib.h>   
    #include <linux/input.h>   
    #include <fcntl.h>   
    #include <sys/time.h>   
    #include <sys/types.h>   
    #include <sys/stat.h>   
    #include <unistd.h>   
      
      
    int main(int argc,char **argv)  
    {  
        int fd, retval;  
        char buf[6];  
        fd_set readfds;  
        struct timeval tv;  
      
        //fd = open("/dev/input/mice", O_RDONLY);   
        if(( fd = open("/dev/input/mice", O_RDONLY))<0)  
        {  
            printf("Failed to open \"/dev/input/mice\".\n");  
            exit(1);  
        }  
        else  
        {  
            printf("open \"/dev/input/mice\" successfuly.\n");  
        }  
      
        while(1)  
        {  
            tv.tv_sec = 5;  
            tv.tv_usec = 0;  
      
            FD_ZERO(&readfds);  
            FD_SET(fd, &readfds);  
      
            retval = select(fd+1, &readfds, NULL, NULL, &tv);  
            if(retval==0)  
            printf("Time out!\n");  
            if(FD_ISSET(fd,&readfds))  
            {  
                if(read(fd, buf, 6) <= 0)//终端设备,一次只能读取一行   
                {  
                    continue;  
                }  
                printf("Button type = %d, X = %d, Y = %d, Z = %d\n", (buf[0] & 0x07), buf[1], buf[2],   buf[3]);  
            }  
        }  
        close(fd);  
        return 0;  
    }  

A simple program to check the /dev/input/mouse0 datas

Tested on the raspberry PI with GPM installed

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>

#define MOUSEFILE "/dev/input/mouse0"
//
int main()
{
    int fd;
    struct input_event ie;
    //
    unsigned char button,bLeft,bMiddle,bRight;
    char x,y;
    int absolute_x,absolute_y;

    if((fd = open(MOUSEFILE, O_RDONLY)) == -1) {
        printf("Device open ERROR\n");
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("Device open OK\n");
    }
    //
    printf("right-click to set absolute x,y coordinates origin (0,0)\n");
    while(read(fd, &ie, sizeof(struct input_event)))
    {
        unsigned char *ptr = (unsigned char*)&ie;
        int i;       
        //
        button=ptr[0];
        bLeft = button & 0x1;
        bMiddle = ( button & 0x4 ) > 0;
        bRight = ( button & 0x2 ) > 0;
        x=(char) ptr[1];y=(char) ptr[2];
        printf("bLEFT:%d, bMIDDLE: %d, bRIGHT: %d, rx: %d  ry=%d\n",bLeft,bMiddle,bRight, x,y);
        //
        absolute_x+=x;
        absolute_y-=y;
        if (bRight==1)
        {
            absolute_x=0;
            absolute_y=0;
            printf("Absolute x,y coords origin recorded\n");
        }
        //
        printf("Absolute coords from TOP_LEFT= %i %i\n",absolute_x,absolute_y);
        //
        // comment to disable the display of raw event structure datas
        //
        for(i=0; i<sizeof(ie); i++)
        {
            printf("%02X ", *ptr++);
        }
        printf("\n");
    }

return 0;
}

The read() command is blocking for now.
The following C code does almost the same thing, with non-blocking option enabled this time:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>

#define MOUSEFILE "/dev/input/mouse0\0"
//
int main()
{
    int fd;
    struct input_event ie;
    unsigned char *ptr = (unsigned char*)&ie;
    //
    unsigned char button,bLeft,bMiddle,bRight;
    char x,y;                                                            // the relX , relY datas
    int absolute_x,absolute_y;

    if((fd = open(MOUSEFILE, O_RDONLY | O_NONBLOCK )) == -1)
    {
        printf("NonBlocking %s open ERROR\n",MOUSEFILE);
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("NonBlocking %s open OK\n",MOUSEFILE);
    }
    //
    printf("--------------------------------------------------------\n");
    printf("right-click to set absolute x,y coordinates origin (0,0)\n");
    printf("left+right click to EXIT\n");
    printf("--------------------------------------------------------\n");
    //
    while(1)
    {       
        if(read(fd, &ie, sizeof(struct input_event))!=-1)
        {
            //
            button=ptr[0];
            bLeft = button & 0x1;
            bMiddle = ( button & 0x4 ) > 0;
            bRight = ( button & 0x2 ) > 0;
            x=(char) ptr[1];y=(char) ptr[2];
            if(bLeft&bRight) { printf("\nright+left ,EXIT\n");break;}
            // computes absolute x,y coordinates
            absolute_x+=x;
            absolute_y-=y;
            // set absolute reference ?
            if (bRight==1)
            {
                absolute_x=0;
                absolute_y=0;
                printf("Absolute x,y coords origin recorded\n");
            }
            // show it!
            printf("X%i Y%i\n",absolute_x,absolute_y);
            fflush(stdout);
        }
    }
    //
    close(fd);
return 0;
}
广告位

发表评论

你必须 登陆 方可发表评论.