花了将近1周时间来理清之前模糊的概念,感觉思路清晰了很多,今天是八天内容中的最后一天。以后的内容就不会每天都写文章了。今天的内容还是关于鼠标的控制,但是是让它真正的动起来。
在主函数中,我们取得了鼠标的数据。
for (;;) {
io_cli();
if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
io_stihlt();
} else {
if (fifo8_status(&keyfifo) != 0) {
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
} else if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
if (mouse_phase == 0) {
/* 等待鼠标的0xfa的状态 */
if (i == 0xfa) {
mouse_phase = 1;
}
} else if (mouse_phase == 1) {
/* 等待鼠标的第一字节 */
mouse_dbuf[0] = i;
mouse_phase = 2;
} else if (mouse_phase == 2) {
/* 等待鼠标的第二字节 */
mouse_dbuf[1] = i;
mouse_phase = 3;
} else if (mouse_phase == 3) {
/* 等待鼠标的第三字节 */
mouse_dbuf[2] = i;
mouse_phase = 1;
/* 鼠标的3个字节都齐了,显示出来 */
sprintf(s, "%02X %02X %02X", mouse_dbuf[0], mouse_dbuf[1], mouse_dbuf[2]);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 8 * 8 - 1, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
}
}
}
}
这段程序首先要把最初读到的0xfa舍弃掉,之后每次从鼠标那里过来的数据都是3个字节一组的,所以当数据累积到3个字节,就把它显示到屏幕上。
接下来是对这3个字节的数据进行解读,当鼠标移动或者点击左右中按键时,相对应的字节会有变化,解读代码如下:
if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
if (mouse_decode(&mdec, i) != 0) {
/* 数据的3个字节都齐了,显示出来 */
sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
if ((mdec.btn & 0x01) != 0) {
s[1] = 'L';
}
if ((mdec.btn & 0x02) != 0) {
s[3] = 'R';
}
if ((mdec.btn & 0x04) != 0) {
s[2] = 'C';
}
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
}
}
int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
if (mdec->phase == 0) {
/* 等待鼠标的0xfa的阶段 */
if (dat == 0xfa) {
mdec->phase = 1;
}
return 0;
}
if (mdec->phase == 1) {
/* 等待鼠标第一字节的阶段 */
if ((dat & 0xc8) == 0x08) {
/* 如果第一字节正确 */
mdec->buf[0] = dat;
mdec->phase = 2;
}
return 0;
}
if (mdec->phase == 2) {
/* 等待鼠标第二字节的阶段 */
mdec->buf[1] = dat;
mdec->phase = 3;
return 0;
}
if (mdec->phase == 3) {
/* 等待鼠标第三字节的阶段 */
mdec->buf[2] = dat;
mdec->phase = 1;
mdec->btn = mdec->buf[0] & 0x07;
mdec->x = mdec->buf[1];
mdec->y = mdec->buf[2];
if ((mdec->buf[0] & 0x10) != 0) {
mdec->x |= 0xffffff00;
}
if ((mdec->buf[0] & 0x20) != 0) {
mdec->y |= 0xffffff00;
}
mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */
return 1;
}
return -1; /* 不会执行到这里 */
}
在if (mdec->phase == 1) 的if ((dat & 0xc8) == 0x08)判断中,用于判断第一字节对移动有反应的部分是否在0~3的范围内,同时还要判断第一字节对点击有反应的部分是否在8~F的范围内。如果这个字节的数据不在以上范围内,它就会被舍去。
最后的if (mdec->phase == 3)是解读处理的核心。鼠标键的状态放在buf[0]的低3位,x和y的数据直接使用buf[1]和buf[2]。
解读完这些数据之后,最后就是要让鼠标真正动起来了。其实让其动起来很简单,只需要将之前的图标隐藏之后重新描绘,就能实现了。核心实现如下:
if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
if (mouse_decode(&mdec, i) != 0) {
/* 数据的3个字节都齐了,显示出来 */
sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
if ((mdec.btn & 0x01) != 0) {
s[1] = 'L';
}
if ((mdec.btn & 0x02) != 0) {
s[3] = 'R';
}
if ((mdec.btn & 0x04) != 0) {
s[2] = 'C';
}
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
/* 鼠标指针的移动 */
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, mx, my, mx + 15, my + 15); /* 隐藏鼠标 */
mx += mdec.x;
my += mdec.y;
if (mx < 0) {
mx = 0;
}
if (my < 0) {
my = 0;
}
if (mx > binfo->scrnx - 16) {
mx = binfo->scrnx - 16;
}
if (my > binfo->scrny - 16) {
my = binfo->scrny - 16;
}
sprintf(s, "(%3d, %3d)", mx, my);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* 隐藏坐标 */
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* 显示坐标 */
putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16); /* 描画鼠标 */
}
}
至此就完成了鼠标的移动,但是这段程序还是有问题,当鼠标移动到下面的任务栏,就会覆盖掉,需要考虑到叠加处理问题,这个就是后续要处理的事情了。