第八天 - 鼠标控制与32位模式切换

鼠标控制与32位模式切换

一、鼠标控制

1. 鼠标数据解读

unsigned char mouse_dbuf[3], mouse_phase;

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;
                    /* 鼠标的三个字节都齐了,显示出来 */
                    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);
                }
            }
		}
    }
  • mouse_phase用于记录鼠标工作状态的数组
  • 如果检测到有键盘数据,则根据鼠标的状态进行处理
  • 鼠标数据一般是三个字节一组,读到三个字节数据就调用显示写入显存,然后显示在屏幕上

2. 代码整理

  • 将鼠标相关的变量用结构体进行存储,剥离鼠标数据的逻辑为独立的函数

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

void enable_mouse(struct MOUSE_DEC *mdec)
{
    /* 激活鼠标 */
    wait_KBC_sendready();
    io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
    wait_KBC_sendready();
    io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
    /* 顺利的话,ACK(0xfa)会被传送过来 */
    mdec->phase = 0;    /* 等待0xfa的阶段 */
    return;
}

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) {
        /* 等待鼠标第一字节的阶段 */
        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;
        return 1;
    }
    return -1; /* 应该不可能到这里来 */
}

3. 鼠标数据解读

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存储移动的xy轴信息,btn存储鼠标按键的状态信息
  • mouse_phase == 1 时:
    • 0x08 的二进制形式是 0000 1000
    • 按位与 用于判断第一个字节对移动有反应的部分是否在03之间,对点击有反应的部分是否在8F之间,防止因鼠标连接问题而导致的数据丢失,从而导致数据错位而无法正确读取鼠标的信息
  • mouse_phase == 3 时:
    • 鼠标的状态放在bug[0]的低三位,0x07 == 0000 0111, 按位与去获取第三位的鼠标键的状态
    • 为了正确解读xy的数据,需要使用第一字节的对移动有反应的几位信息,将xy的第八位和之后的数据全部设为1,或者全部保留位0
    • 0x20 == 0010 0000, 如果按位与位部位0则表示 第三位为1,需要全部置为 1, 0xffffff00 == 1111.... 0000 0000
    • 解读最后需要对y轴去反,因为鼠标和屏幕的y方向是相反的

鼠标数据的显示

 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_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与 0000 0001 按位与判断最低位是否为1,也就是是否要转为大写字符

4. 移动鼠标指针

posted @   bingekong  阅读(33)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示