AllenYao 发表于 2006-11-14 22:10:51

涂鸦乱画

经过几天的努力,终于完成了涂鸦程序。本来是想找到Linux下对鼠标的控制编程方法,后来结合Framebuffer就想干脆做出一个涂鸦程序来,这样既学习了编程,又体现了乐趣^0^。

其实,我并没有找到Linux下对鼠标进行编程的资料。但是,在Linux公社里看到,使用“cat /dev/input/mice”命令,移动鼠标,屏幕上就会不时地打印出一些乱码字符来。于是,我设想是不是可以像普通文件一样打开这个设备文件,然后不停地读取其中的数据。根据PS/2鼠标协议(可以在网上查到),这个数据应该是3个字节一组,其中第1个字节表示是鼠标的状态,第2个字节和第3个字节分别表示X,Y方向上的移动量(这里使用的坐标与Framebuffer屏幕坐标一样,即X轴从左至右是正方向,Y轴从上至下是正方向)。于是我编写了一个小程序测试,果然!

在进一步编写涂鸦程序时,我遇到了几个困难。第1个困难是,负数的转换。好久没有接触到负数了,几乎全忘了。上网一查,才知道此仍《微机原理》的基础。即计算机中有符号数都是使用补码来表示的。第2个困难是,如何让程序运行起来后不立即结束。这个我还没有解决。本想通过按任意键退出的方式,可是read stdin会阻塞。虽然想到可以使用select函数,但是还没有试验。暂时就按Ctrl+C退出程序吧^0^。第3个困难是,如何在两点之间画线。这个其实是学习Framebuffer时还没有完成的部分。这次为了体现鼠标的运动轨迹,必须要画线。无奈,我的数学知道都忘光了(要上小学补习了)。我只好抄了别人的代码来用。

附程序代码,开发环境是Arch Linux,Framebuffer vga=789,编译命令“gcc -Wall doodle.c -lm”。

/******************************************************************************
* doodle.c
*
* allen
* 2006/11/14
******************************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <math.h>

#define COLOR_BLUE255
#define COLOR_GREEN 65280
#define COLOR_RED   16711680

char *fbp = 0;
int xres = 0;
int yres = 0;
int bits_per_pixel = 0;

char kb_hit( void );
void draw_point(int x, int y, unsigned int color);
void draw_line( int x1, int y1, int x2, int y2, unsigned int c );
void draw_hline(int x, int y, int width, int color);
void draw_vline(int x, int y, int heigth, int color);

/******************************************************************************
*
******************************************************************************/
int main()
{
    int fbfd = 0, micefd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;
    char miceinfo[3];
    int last_x = 0, last_y = 0;
    int cursor_x = 0, cursor_y = 0;
int addx, addy;

    if (0 > (micefd = open( "/dev/input/mice", O_RDONLY )))
{
printf("Error: cannot open mice device.\n");
return( 0 );
}

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (!fbfd)
    {
      printf("Error: cannot open framebuffer device.\n");
      close( micefd );
      return( 0 );
    }

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
    {
      printf("Error reading fixed information.\n");
      close( micefd );
      return( 0 );
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
    {
      printf("Error reading variable information.\n");
      close( micefd );
      return( 0 );
    }

    xres = vinfo.xres;
    yres = vinfo.yres;
    bits_per_pixel = vinfo.bits_per_pixel;

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                     fbfd, 0);
    if ((int)fbp == -1)
    {
      printf("Error: failed to map framebuffer device to memory.\n");
      close( micefd );
      return( 0 );
    }
   
    last_x = cursor_x = xres / 2;
    last_y = cursor_y = yres / 2;
   
    draw_point( cursor_x, cursor_y, COLOR_RED );

while(1)
{
memset( miceinfo , 0x00, sizeof(miceinfo) );
if (0 > read( micefd, miceinfo, sizeof(miceinfo) ))
{
   break;
   break;
}

addx = (int)miceinfo[1];
addy = 0 - (int)miceinfo[2];

printf( "x_move : [%d]    y_move : [%d]\n", addx, addy );
fflush( stdout );

if (((cursor_x + addx) < 800) && ((cursor_x + addx) >= 0))
{
   last_x = cursor_x;
   cursor_x += addx;
}

if (((cursor_y + addy) < 600) && ((cursor_y + addy) >= 0))
{
   last_y = cursor_y;
   cursor_y += addy;
}

draw_line( last_x, last_y, cursor_x, cursor_y, COLOR_RED );
}

    munmap( fbp, screensize );
    close( fbfd );
    close( micefd );
    return 0;
}

/******************************************************************************
*
******************************************************************************/
char kb_hit( void )
{
    char c   ;
    intret ;

    ret = read(STDIN_FILENO, &c, 1);

    return (ret == -1) ? 0 : c;
}

/******************************************************************************
* 画点函数
******************************************************************************/
void draw_point(int x, int y, unsigned int color)
{
   long int location = 0;
   
   location = x * bits_per_pixel / 8 + y * xres * bits_per_pixel / 8;

   memcpy( (fbp + location), &color, 4 );
   
   return;
}

/******************************************************************************
* 画线函数
******************************************************************************/
void draw_line( int x1, int y1, int x2, int y2, unsigned int c )
{
    int dx= x2 - x1;
    int dy= y2 - y1;
    int n, b;
    float m;

    if(0 == dx)
    {
      if(dy < 0)
            for(n = y1; n >= y2; n--)
                draw_point( x1, n, c);
      else
            for(n = y1; n <= y2; n++)
                draw_point( x1, n, c);
    }
    else if(0 == dy)
    {
      if(dx < 0)
            for(n = x1; n >= x2; n--)
                draw_point( n, y1, c);
      else
            for(n = x1; n <= x2; n++)
                draw_point( n, y1, c);
    }
    else if(abs(dx) >= abs(dy))
    {
      m = ((float)dy) / ((float)dx);
      b = (int)(y1 - m * x1);
      if(dx < 0)
            for(n = x1; n >= x2; n--)
                draw_point( n, (u_int)floor(n * m + b + 0.5), c);
      else
            for(n = x1; n <= x2; n++)
                draw_point( n, (u_int)floor(n * m + b + 0.5), c);
    }
    else
    {
      m = ((float)dx) / ((float)dy);
      b = (int)(x1 - m * y1);
      if(dy < 0)
            for(n = y1; n >= y2; n--)
                draw_point( (u_int)floor(n * m + b + 0.5), n, c);
      else
            for(n = y1; n <= y2; n++)
                draw_point( (u_int)floor(n * m + b + 0.5), n, c);
    }
return;
}

asmcos 发表于 2006-11-15 09:25:43

好。
页: [1]
查看完整版本: 涂鸦乱画