14.移动鼠标

news/2024/11/22 19:13:50/

简介

鼠标发送的数据要三个字节一起解读,所以我们的内核要等待鼠标发送足够的数据后才可以采取行动。当鼠标被激活后,它会立马给内核发送一个字节数据,数值为0xfa, 当内核收到这个数据后,就可以开始积攒数据,每接收三个字节后,根据数据绘制鼠标。

这三个字节数据是有一定特点的,第一个字节0xmn, m的数值必须在0-3这个范围内,所以这意味着该字节的第6、7两个比特位必须为0,n的值必须在8-F之间,这意味着该字节数据对应的第4个比特位必须为1。左键,滚轮,右键被按下时,n的最低3位会被置1。

第二个字节用来表示鼠标的左右移动,对该字节进行相应处理后,可以得到鼠标平移的坐标变换。

第三个字节的数据表示鼠标的上下移动,对该字节进行相应处理后,可以得到鼠标垂直移动时的坐标变换。

目标

1.os.h 文件定义MouseDes处理鼠标移动数据类型,os.h文件如下:

//*******************************相关数据类型声明*************************//定义调色板颜色
#define  COL8_000000  0
#define  COL8_FF0000  1
#define  COL8_00FF00  2
#define  COL8_FFFF00  3
#define  COL8_0000FF  4
#define  COL8_FF00FF  5
#define  COL8_00FFFF  6
#define  COL8_FFFFFF  7
#define  COL8_C6C6C6  8
#define  COL8_840000  9
#define  COL8_008400  10
#define  COL8_848400  11
#define  COL8_000084  12
#define  COL8_840084  13
#define  COL8_008484  14
#define  COL8_848484  15//屏幕宽度
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200//定义缓冲区
typedef struct _FIFO8{//指向缓冲区char* buf;//r:读索引,w:写索引//len:存储数据长度int r, w, size, len, flag;
}FIFO8;//定义鼠标移动处理模型
//鼠标处理需要连续处理3字节
//phase 表三处理的字节阶段
//offX,offY 表示当前鼠标的偏移
//x,y 表示鼠标当前所在的坐标位置
typedef struct _MouseDes{char buf[3], phase;int offX,offY;int x, y, btn;
}MouseDes;//*******************************函数声明*************************//初始化调色板
void initPallet();/***绘制矩形*x             矩形左上角x坐标*y             矩形左上角y坐标*width         宽度*height        高度*colIndex      pallet_color 类型调色板颜色索引,即矩形颜色*/void fillRect(int x,int y,int width,int height,char colIndex);//绘制桌面背景
void drawBackground();/***绘制字体*@param	addr		绘制的起始显存地址*@param 	x			绘制的x坐标*@param	y			绘制的y坐标*@param	col			绘制颜色*@param	pch			绘制的字符数组8*16,每一行共8位,共16行*@param	screenWidth	屏幕宽度*/
void putChar(char *addr,int x,int y,char col,unsigned char *ch,int screenWidth);/**初始化鼠标指针*@param	vram		绘制的起始显存地址*@param	x			绘制鼠标指针最左上角x坐标*@param	y			绘制鼠标指针最左上角y坐标*@param	bc			绘制的矩形填充颜色,和背景色一样将能看到鼠标指针*/
void drawMouseCursor(char *vram,int x,int y,char bc);/**char 类型数据转换为16进制字符数据*@param	val		待转化为16进制的数值*@param	arr		保存16进制字符串数据的数组*/
void char2HexStr(unsigned char val,char *arr);//初始化鼠标硬件
void init_mouse();//缓存初始化
void fifo8_init(FIFO8 *fifo,int size,char *buf);
//缓冲区存放数据
int fifo8_put(FIFO8 *fifo,char data);
//缓冲区读取数据
int fifo8_get(FIFO8 *fifo);//鼠标移动处理
//@param	mdec		鼠标移动处理模型
//@param	bc			绘制鼠标的背景色
void mouseCursorMoved(MouseDes *mdec,char bc);

2.os.c 文件如下:

// !compile method
// clang -m32 -c os.c -o os.o
// objconv -fnasm os.o -o os.s
//#include "os.h"
#include "io.h"
#include "ascii_font.h"static char keybuf[32];
static char mousebuf[128];static FIFO8 keybufInfo;
static FIFO8 mousebufInfo;//鼠标移动模型
static MouseDes mouseDes;static int num = 0;//操作系统C语言入口函数--可以指定为其他
void init_main() {io_sti();initPallet();drawBackground();fifo8_init(&keybufInfo,32,keybuf);fifo8_init(&mousebufInfo,128,mousebuf);mouseDes.x = (320-16)/2;mouseDes.y = (200-16)/2;mouseDes.phase = 0;drawMouseCursor((char *)0xa0000,mouseDes.x,mouseDes.y,COL8_008484);init_mouse();for(; ;){if(keybufInfo.len>0){io_cli();static char arr[4] = {'0','x'};unsigned char *ascii = ascii_array;for(int t=0;t<keybufInfo.len;t++){char data = fifo8_get(&keybufInfo);char2HexStr(data,arr);for(int i=0;i<4;i++){int x = (num)%32*10;int y = (num)/32*20;putChar((char *)0xa0000,x,y,COL8_FFFFFF,ascii+(arr[i]-0x20)*16,SCREEN_WIDTH);num++;}}io_sti();}else if(mousebufInfo.len>0){io_cli();for(int t=0;t<mousebufInfo.len;t++){mouseCursorMoved(&mouseDes,COL8_008484);}io_sti();}else{io_hlt();}}}void initPallet(){//定义调色板static char table_rgb[16*3] = {0x00,  0x00,  0x00,		/*  0:黑色*/0xff,  0x00,  0x00,		/*  1:亮红*/0x00,  0xff,  0x00,		/*  2:亮绿*/0xff,  0xff,  0x00,		/*  3:亮黄*/0x00,  0x00,  0xff,		/*  4:亮蓝*/0xff,  0x00,  0xff,		/*  5:亮紫*/0x00,  0xff,  0xff,		/*  6:浅亮蓝*/0xff,  0xff,  0xff,		/*  7:白色*/0xc6,  0xc6,  0xc6,		/*  8:亮灰*/0x84,  0x00,  0x00,		/*  9:暗红*/0x00,  0x84,  0x00,		/* 10:暗绿*/0x84,  0x84,  0x00,		/* 11:暗黄*/0x00,  0x00,  0x84,		/* 12:暗青*/0x84,  0x00,  0x84,		/* 13:暗紫*/0x00,  0x84,  0x84,		/* 14:浅灰蓝*/0x84,  0x84,  0x84,		/* 15:暗灰*/};unsigned char *rgb = (unsigned char *)table_rgb;int flag = io_readFlag();io_cli();io_out8(0x03c8, 0);for(int i=0;i<16;i++){io_out8(0x03c9,rgb[0] / 4);io_out8(0x03c9,rgb[1] / 4);io_out8(0x03c9,rgb[2] / 4);rgb += 3;}io_writeFlag(flag);
}void fillRect(int x,int y,int width,int height,char colIndex){char *vram = (char *)0xa0000;for(int i=y;i<=y+height;i++){for(int j=x;j<=x+width;j++){vram[i*SCREEN_WIDTH+j] = colIndex;}}
}void drawBackground(){fillRect(0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-29, COL8_008484);fillRect(0,SCREEN_HEIGHT-28,SCREEN_WIDTH-1,28, COL8_848484);fillRect(0,SCREEN_HEIGHT-27,SCREEN_WIDTH,1, COL8_848484);fillRect(0,SCREEN_HEIGHT-26,SCREEN_WIDTH,25, COL8_C6C6C6);fillRect(3,SCREEN_HEIGHT-24,56,1, COL8_FFFFFF);fillRect(2,SCREEN_HEIGHT-24,1,20, COL8_FFFFFF);fillRect(3,SCREEN_HEIGHT-4,56,1, COL8_848484);fillRect(59,SCREEN_HEIGHT-23,1,19, COL8_848484);fillRect(2,SCREEN_HEIGHT-3,57,0, COL8_000000);fillRect(60,SCREEN_HEIGHT-24,0,19, COL8_000000);fillRect(SCREEN_WIDTH-47,SCREEN_HEIGHT-24,43,1, COL8_848484);fillRect(SCREEN_WIDTH-47,SCREEN_HEIGHT-23,0,19, COL8_848484);fillRect(SCREEN_WIDTH-47,SCREEN_HEIGHT-3,43,0, COL8_FFFFFF);fillRect(SCREEN_WIDTH-3,SCREEN_HEIGHT-24,0,21, COL8_FFFFFF);
}void putChar(char *addr,int x,int y,char col,unsigned char *pch,int screenWidth){for(int i=0;i<16;i++){char ch = pch[i];int off = (y+i)*screenWidth;//显示的字形最左边的是低地址,右侧的是高地址。例如:0x80,则高地址部分显示在内存的低地址,//最低位的应该偏移7if((ch & 0x01) != 0){addr[off+x+7] = col;}if((ch & 0x02) != 0){addr[off+x+6] = col;}if((ch & 0x04) != 0){addr[off+x+5] = col;}if((ch & 0x08) != 0){addr[off+x+4] = col;}	if((ch & 0x10) != 0){addr[off+x+3] = col;}if((ch & 0x20) != 0){addr[off+x+2] = col;}if((ch & 0x40) != 0){addr[off+x+1] = col;}	if((ch & 0x80) != 0){addr[off+x+0] = col;}}
}void drawMouseCursor(char *vram,int x,int y,char bc){//16*16 Mouse //鼠标指针点阵static char cursor[16][16] = {"*...............","**..............","*O*.............","*OO*............","*OOO*...........","*OOOO*..........","*OOOOO*.........","*OOOOOO*........","*OOOOOOO*.......","*OOOO*****......","*OO*O*..........","*O*.*O*.........","**..*O*.........","*....*O*........",".....*O*........","......*........."};for (int i = 0; i < 16; i++) {for (int j = 0; j < 16; j++) {int off = (i+y)*SCREEN_WIDTH+x+j;if (cursor[i][j] == '*') {vram[off] = COL8_000000;}if (cursor[i][j] == 'O') {vram[off] = COL8_FFFFFF;}if (cursor[i][j] == '.') {vram[off] = bc;}}}}void char2HexStr(unsigned char val,char *arr) {unsigned char tmp = val >> 4;if(tmp>=10){arr[2] = 'a'+tmp-10;}else{arr[2] = '0'+tmp;}tmp = val & 0x0f;if(tmp>=10){arr[3] = 'a'+tmp-10;}else{arr[3] = '0'+tmp;}
}/**8259A 键盘中断调用**/
void int_keyboard(char *index){//0x20是8259A控制端口//0x21对应的是键盘的中断向量。当键盘中断被CPU执行后,下次键盘再向CPU发送信号时,//CPU就不会接收,要想让CPU再次接收信号,必须向主PIC的端口再次发送键盘中断的中断向量号io_out8(0x20,0x21);//读取8259A  0x60端口键盘扫描码char data = io_in8(0x60);fifo8_put(&keybufInfo,data);
}#define  PORT_KEYDAT  0x60
#define  PORT_KEYSTA  0x64
#define  PORT_KEYCMD  0x64
#define  KEYCMD_WRITE_MODE  0x60
#define  KBC_MODE     0x47//鼠标电路对应的一个端口是 0x64, 通过读取这个端口的数据来检测鼠标电路的状态,
//内核会从这个端口读入一个字节的数据,如果该字节的第二个比特位为0,那表明鼠标电路可以
//接受来自内核的命令,因此,在给鼠标电路发送数据前,内核需要反复从0x64端口读取数据,
//并检测读到数据的第二个比特位,直到该比特位为0时,才发送控制信息
void waitKBCReady(){for( ; ;){if((io_in8(PORT_KEYSTA) & 0x02)==0){break;}}
}#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4//初始化键盘控制电路,鼠标控制电路是连接在键盘控制电路上,通过键盘电路实现初始化
void init_mouse(){waitKBCReady();//0x60让键盘电路进入数据接受状态io_out8(PORT_KEYCMD,KEYCMD_WRITE_MODE);waitKBCReady();//数据0x47要求键盘电路启动鼠标模式,这样鼠标硬件所产生的数据信息,通过键盘电路端口0x60就可读到io_out8(PORT_KEYDAT,KBC_MODE);	waitKBCReady();io_out8(PORT_KEYCMD,KEYCMD_SENDTO_MOUSE);waitKBCReady();//0xf4数据激活鼠标电路,激活后将会给CPU发送中断信号io_out8(PORT_KEYDAT,MOUSECMD_ENABLE);
}/**8259A 鼠标中断调用**/
void int_mouse(char *index){//当中断处理后,要想再次接收中断信号,就必须向中断控制器发送一个字节的数据io_out8(0x20,0x20);io_out8(0xa0,0x20);//读取鼠标数据char data = io_in8(0x60);fifo8_put(&mousebufInfo,data);
}void fifo8_init(FIFO8 *fifo, int size,char *buf){fifo->buf = buf;fifo->r = 0;fifo->w = 0;fifo->size = size;fifo->len = 0;fifo->flag = 0;
}int fifo8_put(FIFO8 *fifo,char data){if (fifo->len == fifo->size) {return -1;}fifo->buf[fifo->w] = data;fifo->w++;if (fifo->w == fifo->size) {fifo->w = 0;}fifo->len++;return 0;
}int fifo8_get(FIFO8 *fifo) {if (fifo->len == 0) {return -1;}int data = fifo->buf[fifo->r];fifo->r++;if (fifo->r == fifo->size) {fifo->r = 0;}fifo->len--;return data;
}int mouse_decode(MouseDes *mdec,unsigned char dat){ int flag = -1;if (mdec->phase == 0) { if (dat == 0xfa) { mdec->phase = 1; } flag = 0;} else if (mdec->phase == 1) { if ((dat & 0xc8) == 0x08) { mdec->buf[0] = dat; mdec->phase = 2; } flag = 0;} else if (mdec->phase == 2) { mdec->buf[1] = dat; mdec->phase = 3; flag = 0;} else if (mdec->phase == 3) { mdec->buf[2] = dat; mdec->phase = 1; mdec->btn = mdec->buf[0] & 0x07; mdec->offX = mdec->buf[1]; mdec->offY = mdec->buf[2]; if ((mdec->buf[0] & 0x10) != 0) { mdec->offX |= 0xffffff00; } if ((mdec->buf[0] & 0x20) != 0) { mdec->offY |= 0xffffff00; } //鼠标y坐标偏移和平面y坐标相反mdec->offY = -mdec->offY; flag = 1; } return flag; 
}//鼠标移动处理
void mouseCursorMoved(MouseDes *mdec,char bc){unsigned char val = fifo8_get(&mousebufInfo);//表示处理到第3步,需要绘制鼠标光标if(mouse_decode(mdec,val) == 1) {fillRect(mdec->x,mdec->y,16,16,bc);mdec->x += mdec->offX;mdec->y += mdec->offY;if(mdec->x < 0){mdec->x = 0;}if(mdec->x > SCREEN_WIDTH-16/2){mdec->x = SCREEN_WIDTH-16/2;}if(mdec->y < 0 ){mdec->y = 0;}if(mdec->y > SCREEN_HEIGHT - 16){mdec->y = SCREEN_HEIGHT - 16;}drawMouseCursor((char *)0xa0000,mdec->x,mdec->y,bc);}
}

3.编译并加载floppy.img 文件,让虚拟机捕获鼠标后效果如同pc 上移动鼠标一样真切!如下图为鼠标从平面中间移动后的位置,平面上的文字可不用理会(笔者在Ubuntu 操作系统下开发,使用VirtualBox虚拟机在Ubuntu下加载floppy.img 文件,在截屏使需要按下 左 shift 键导致的输出)
在这里插入图片描述

说明

当收到字节0xfa的时候,系统进入数据收集阶段,当收到第一个数据时,判断字节是否符合前面所说的要求,符合的话,进入第二阶段,接收第二个字节,当进入第三阶段,接收完第三个字节后,开始对坐标数据进行处理,btn存储的是第一字节的低3位,它表示当前鼠标哪个按键被按下了,接着看第一字节的第4,第5个比特位,如果第4、5个比特位为1,那么第二、三字节需要做一些处理,也就是从第8位开始全部设置为1。


http://www.ppmy.cn/news/163590.html

相关文章

PaaS平台iuap——数智底座支撑企业的全球化业务拓展

数智化转型是全球化企业非常关注的话题&#xff0c;数智化转型过程中suo 面临的问题与挑战也绝非一套简单的产品能够解决的&#xff0c;必须配合组织、人员、目标制度采用达成目标。iuap平台是整个企业数智化转型的底座&#xff0c;形象来说是我们的土壤&#xff0c;在这个土壤…

基于Python+OpenCV的图像搜索引擎(CBIR+深度学习+机器视觉)含全部工程源码及图片数据库下载资源

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 定义图像描述符3. 索引化数据集4. 设计搜索引擎内核5. 执行搜索 系统测试1. 处理数据集2. 执行搜索 工程源代码下载其它资料下载 前言 本项目旨在开发一套完整高效的图像搜索引擎&#xff0c;为用…

C 语言详细教程

目录 第一章 C语言基础知识 第二章 数据类型、运算符和表达式 第三章 结构化程序设计 第四章 数组 第五章 函数 第六章 指针 第七章 结构体类型和自定义类型 第八章 编译预处理 第九章 文件 说明&#xff1a;本教程中的代码除一二三个之外&#xff0c;都在https://ligh…

相机的格式

图片的格式大体上可以分为yuv格式和RGB格式&#xff0c;以及png,jpg格式&#xff1b; 其中yuv格式对应的摄像头的格式可以是YUYV、UYVV、YVYU、VYUY&#xff1b; rgb格式的图片对应的摄像头格式为RGB,BGR,ARGB8888格式&#xff1b; 一、RGB8888和ARGB8888像素格式如果搞混了…

第二十二章行为型模式—备忘录模式

文章目录 备忘录模式解决的问题结构实例“白箱” 备忘录模式“黑箱” 备忘录模式 存在的问题适用场景 行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分…

Raspberry pi 4 安装tenda u1 无线网卡

树莓派4的无线网卡信号不怎么样&#xff0c;速度上不去&#xff0c;还总是断掉&#xff0c;买了个tenda u1 的usb网卡&#xff0c;结果没有linux驱动。。。 安装方式&#xff1a; 先安装驱动编译的一些依赖 #apt install linux-headers u10用的是8821cu芯片&#xff0c;下载…

Win10,Cuda 11.1 下载与安装

1、地址&#xff1a;https://developer.nvidia.com/cuda-toolkit-archive&#xff0c;选择版本 选择配置&#xff0c;下载安装包 2、点击cuda_11.1.1_456.81_win10.exe文件安装 等待安装 3、安装 最后点击关闭就可以啦。 5、命令窗口输入 nvcc -V&#xff0c;查看是否安装成功…

python安装cfgrib读取grib数据

尝试用xarray基于cfgrib库读取grib数据&#xff0c;通过pip命令安装也成了&#xff0c;提示如下 Found: ecCodes v2.27.0. Your system is ready.然而&#xff0c;尝试import cfgrib时&#xff0c;仍然提示 RuntimeError: Cannot find the ecCodes library 本身确认ecmwflibs、…