QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2536|回复: 1

涂鸦乱画

[复制链接]
发表于 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”。
[code:1]
/******************************************************************************
* 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_BLUE  255
#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   ;
    int  ret ;

    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;
}
[/code:1]
发表于 2006-11-15 09:25:43 | 显示全部楼层
好。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-5-3 06:42 , Processed in 0.053346 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表