30天自制操作系统
上QQ阅读APP看书,第一时间看更新

3 鼠标解读(2)(harib05c)

程序已经很清晰了,我们继续解读程序。首先对mouse_decode函数略加修改。

bootpack.c节选

struct MOUSE_DEC {
    unsigned char buf[3], phase;
    int x, y, btn;
};

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; /* 应该不会到这儿来 */
}

■■■■■

结构体里增加的几个变量用于存放解读结果。这几个变量是x、y和btn,分别用于存放移动信息和鼠标按键状态。

另外,笔者还修改了if(mdec->phase==1)语句。这个if语句,用于判断第一字节对移动有反应的部分是否在0~3的范围内;同时还要判断第一字节对点击有反应的部分是否在8~F的范围内。如果这个字节的数据不在以上范围内,它就会被舍去。

虽说基本上不这么做也行,但鼠标连线偶尔也会有接触不良、即将断线的可能,这时就会产生不该有的数据丢失,这样一来数据会错开一个字节。数据一旦错位,就不能顺利解读,那问题可就大了。而如果添加上对第一字节的检查,就算出了问题,鼠标也只是动作上略有失误,很快就能纠正过来,所以笔者加上了这项检查。

■■■■■

最后的if(mdec->phase==3)部分,是解读处理的核心。鼠标键的状态,放在buf[0]的低3位,我们只取出这3位。十六进制的0x07相当于二进制的00000111,因此通过与运算(&),可以很顺利地取出低3位的值。

x和y,基本上是直接使用buf[1]和buf[2],但是需要使用第一字节中对鼠标移动有反应的几位(参考第一节的叙述)信息,将x和y的第8位及第8位以后全部都设成1,或全部都保留为0。这样就能正确地解读x和y。

在解读处理的最后,对y的符号进行了取反的操作。这是因为,鼠标与屏幕的y方向正好相反,为了配合画面方向,就对y符号进行了取反操作。

■■■■■

这样,鼠标数据的解读就完成了。现在我们来修改一下显示部分。

HariMain节选

} else 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);
    }
}

虽然程序中会检查mdec.btn的值,用3个if语句将s的值置换成相应的字符串,不过这一部分,暂时先不要管了。这样,程序就变成以下这样。

sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
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);

这与以前的程序很相似,仅仅用来显示字符串。现在加上刚才的if语句:

if ((mdec.btn & 0x01) ! = 0) {
    s[1] = 'L';
}

这行程序的意思是,如果mdec.btn的最低位是1,就把s的第2个字符(注:第1个字符是s[0])换成‘L'。这就是将小写字符置换成大写字符。其他的if语句也都这样理解吧。

■■■■■

执行一下看看。

反应都很正常,心情大好。