|
经过几天的努力,终于完成了涂鸦程序。本来是想找到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] |
|