您的位置 首页 > 数码极客

「操作系统如何管理鼠标」win7操作系统支持的基本鼠标操作有…

第5天,我们尝试在屏幕上显示了字符串,并且显示了鼠标。

第5天的教程链接:

第5天的显示程序,让当前这个界面,有点像操作系统的样子了

但是,这个鼠标是静止的,所以。我们下一步就是先让鼠标动起来,让屏幕对鼠标的按键和移动操作有响应。

能对鼠标响应之后,再对键盘有响应。

好了,那我们的目标就确定了:让当前的屏幕对鼠标有响应,分别对鼠标的按键和移动有响应。

要做到对鼠标有响应,需要先设置寄存器GDTR, 并生成一个表GDT,然后设置IDTR,并生成一个表IDT。

这个咱们前一天的教程中已经完成了。

具体的,我们可以把获取鼠标按键,移动等代码放在IDT定义的中断函数中去实现,然后再想办法把移动后的鼠标显示到界面上来。

实际上这个IDT和GDT我们在第5天的代码中已经实现了,所以今天完成鼠标的˙中断函数,在中断函数里控制,响应鼠标动作。

只要能够响应鼠标的动作,就可以用鼠标的动作去改变操作系统显示的内容。比如让鼠标指针随着鼠标的动作而改变。

今天的内容会按照以下顺序展开:

  1. 初始化中断相关硬件:中断控制器
  2. 鼠标的中断函数实现分析
  3. C语言写的中断函数
  4. 对中断函数进行优化:将比较耗时的操作移出中断函数

使用中断功能:需要先初始化中断控制硬件

中断控制有专门的硬件:可编程中断控制器,programmable interrupt controller,简称PIC.

下面咱们直接看程序:

void init_pic(void) /* PIC初始化设定 */ { io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ io_out8(PIC0_ICW1, 0x11 ); /* 边沿触发 */ io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2接收 */ io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ io_out8(PIC1_ICW1, 0x11 ); /* 边沿触发 */ io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-接受 */ io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区 */ io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全禁止 */ io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ return; }

程序解读:

PIC0_IMR, 第0个中断控制器的屏蔽寄存器。8位对应8路中断信号。如果某一位为1,那么该位所对应的信号就被屏蔽了,也就是说中断信号产生以后,CPU不会感知到。

这里我们要对中断控制器进行初始化,当然要把中断屏蔽了。所以,我们将PIC0_IMR设置位0xff,将PIC1_IMR设置位0xff.

就是将中断控制器0,中断控制器1的中断信号全部屏蔽了

下面的程序都是有关ICW的设定了。ICW,initial control word,初始化控制数据。也就是把数据写在ICW里,就是对中断控制器初始化。

每个PIC都有4个ICW,ICW1,ICW2,ICW3,ICW4,

ICW1,ICW4主要是设定配线方式。

ICW3设定主从连接方式的,也是8位,如果将其第2位设置位1,那么就是将其第二位作为主从连接用,来接受从中断控制器的中断信号。

ICW2设定中断号,如果设定为0x20,那么当前控制器产生的中断号为:0x20+0,0x20+1,0x20+...,0x20+7,即:0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27.

所以整个init_pic函数主要设定了两个中断控制器PIC0,PIC1,其中,PIC0是主,PIC1是从。

另外,这里使用了OUT指令对PIC的控制字进行操作,因为PIC是CPU的外部设别,CPU只要按照端口去对应写入到控制字就行了。

分别设定了这两个中断控制器的电器连接属性,中断号,以及主从连接属性。

鼠标的中断函数

完成PIC的初始化设定后,硬件上,CPU就可以感知到鼠标的动作了,我们编写中断函数,在感知到鼠标动作后,打印出一些内容就行了。

一般来说,鼠标的中断函数只能在汇编中写,但是这里我们既然用了C语言来写操作系统,自然就想用C语言来写中断函数。

要用C语言写中断函数,就必须用汇编来做桥梁,也就是说在汇编写的中断函数中调用C语言写的中断函数。

汇编写的中断函数只是做一些数据的传递工作,然后调用C语言写的中断函数,不做跟鼠标相关的内容。

我们先来看看汇编写的中断函数,如下:

以下代码摘自:

EXTERN _inthandler2c ; 引入C语言写的中断函数 _asm_inthandler2c: PUSH ES PUSH DS PUSHAD MOV EAX,ESP PUSH EAX MOV AX,SS MOV DS,AX ; make DS=SS MOV ES,AX ; make ES=SS CALL _inthandler2c POP EAX POPAD POP DS POP ES IRETD

可以看到,中间有一句:CALL _inthandler2c

这句代码调用了C语言写的中断函数。

这句代码之外的其他代码,基本上都是push,pop,栈的存入和取出。

也就是说,在这个汇编写的中断函数里,跟鼠标相关的操作,啥都没有做。

这个函数就是调用了C语言中写的中断函数。


如何把汇编中的中断函数放在C语言中实现

如上一段所示,用汇编写一个中断函数,在这个汇编写的中断函数里,调用C写的中断函数就行了。

汇编写的中断函数可以响应系统中断。

因为汇编写的中断函数调用了C语言写的中断函数,所以在它响应系统中断时,C语言写的中断函数就运行起来了。

我们使用C语言写的中断函数来完成对鼠标的响应。

那么C语言写的中断函数如下:

void inthandler2c(int *esp) /* 此函数受汇编中断函数调用 */ { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15); putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 2C (IRQ-12) : PS/2 mouse"); for (;;) { io_hlt(); } }

这个函数内部先是用boxfill8绘制了长方形,然后又在长方形上写了一串字符串:"INT 2C (IRQ-12) : PS/2 mouse"

那么,如果一切正常,将会显示如下画面:


但是,当我们编译完成后,发现并没有出现如上画面。无论是我们滑动鼠标也好,还是点击按钮,都没有反应。

这是因为,鼠标作为计算机的外部设备,也是需要先发送一些控制码,使与鼠标相关的硬件有效。

与鼠标有关的硬件其实就是键盘控制器和鼠标电路了,所以这里要分别给键盘控制器和鼠标发送控制码,如下:

#define PORT_KEYDAT 0x0060 #define PORT_KEYSTA 0x0064 #define PORT_KEYCMD 0x0064 #define KEYSTA_SEND_NOTREADY 0x02 #define KEYCMD_WRITE_MODE 0x60 #define KBC_MODE 0x47 void wait_KBC_sendready(void) { /* 等待键盘控制器准备好 */ for (;;) { if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { break; } } return; } #define KEYCMD_SENDTO_MOUSE 0xd4 #define MOUSECMD_ENABLE 0xf4 void enable_mouse(void) { // 等待键盘控制器准备好 wait_KBC_sendready(); // 给键盘控制器发送命令 io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); // 等待键盘控制器准备好 wait_KBC_sendready(); // 给鼠标发送命令 io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); return; }

将这些代码放在C语言中一起编译,然后运行,就会成功的到如下画面:


到现在为止,系统对鼠标可以响应了:显示字符:PS/2 mouse.

这个正是在我们用C写的中断函数里实现的。


提升中断函数的执行效率:

所谓中断处理,就是打断CPU本来的工作,加塞要求进行处理。

所以必须完成得干净利索。而且进行中断处理期间,不再接受新的中端。

所以如果中断处理程序运行的太慢,它会占用CPU,CPU就无法及时响应新产生的中断。

无法产生新的中断,鼠标如果有新的动作,CPU就无法捕捉到

这将会使CPU无法及时响应用户对鼠标,键盘的操作。

这种现象是我们要极力去避免的。

那么如何做呢?

原则就是中断程序内,只做最简单的事情。

显示一般比较耗时的,

所以,把最耗时的显示程序,放在中断程序外面。

中断程序内,就只是把鼠标的数据保存在某个变量里。

这样,中断程序只完成一个鼠标动作数据的传递功能,对数据的解读,显示等功能,交给main函数就行了。

这样,中断程序就会非常快速地完成,干净利索,cpu就可以更高的频率去捕捉鼠标的动作。

中断程序改成如下形式:

#define PORT_KEYDAT 0x0060 // 定义一个结构体 // 这个结构体用来存放鼠标数据 struct KEYBUF { unsigned char data, flag; }; struct KEYBUF keybuf; void inthandler2c(int *esp) { unsigned char data; io_out8(PIC1_OCW2, 0x64); /* 通知PIC1已经处理完成了IRQ-12的中断 */ io_out8(PIC0_OCW2, 0x62); /* 通知PIC1已经处理完成了IRQ-02的中断 */ data = io_in8(PORT_KEYDAT); if == 0) { keybuf.data = data; keybuf.flag = 1; } return; }

注意到,我们定义了一个结构体KEYBUF,专门用来存放鼠标的端口PORT_KEYDAT传过来的数据。

然后我们再在主程序中,把KEYBUF里的内容显示出来,代码如下:

// boo void HariMain(void) { ... ... ... // 前面是其他带代码 for (;;) { io_cli(); if == 0) { io_stihlt(); } else { i = keybuf.data; keybuf.flag = 0; 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); } } }

以上代码就实现了把原本在中断函数inthandler2c中的显示部分代码,利用keybuf,转移到了HariMain函数中。

不仅实现了对鼠标动作的响应,还实现了中断函数内部的精简。

编译运行成功后,我们发现,我们对鼠标进行各种操作,屏幕上都会成功打印出一个字符出来。

移动鼠标,屏幕出现字符。

点击鼠标按键,屏幕出现字符。

鼠标的响应非常迅速。


但是,屏幕上的鼠标并没有移动。

要想让鼠标移动,就必须在鼠标移动后的位置,去重新绘制一鼠标,

也就是说,我们要完成两个步骤:

1. 获取鼠标的位置

2. 重新绘制鼠标。

那么,如何获取鼠标的位置?

要从keybuf中的data去找。

怎么找?

没办法找,因为data只有一个数值。

鼠标的位置坐标有连个数值:x和y.

所以,data如果是个数组的话,我们就可以把鼠标坐标相关的数据一次性的放入data了。

我们就把data改为数组。然后去按照这个数组来重新绘制鼠标就行了。

那么鼠标返回的数据,难道就只有x,y坐标么?还有其他值么?

有其他值的,比如鼠标按下的是左键,还是右键?鼠标移动时,是每隔一个很短的时候就发送一组x,y的,所以, 鼠标会在很短的时间发送大量的数据。

那么如此大量的数据,显然,如果data这个数组是需要把他们都存储下来的,所以我们需要把data数组优化为一个FIFO的缓冲区

FIFO缓冲区正式为应对鼠标这种短时间大量数据,来不及处理的情况而设计的数据结构,

今天的内容已经很多了,由于FIFO需要讲的比较多,所以我们放在下一天的教程中讲


总结:

今天我们开始对鼠标产生响应了,我们写了对鼠标硬件的控制程序,然后程序能够成功的响应鼠标的移动和按键。我们还为了提高中断函数的效率,把鼠标相关的显示程序放在了HariMain函数中。

但是我们还没有实现把鼠标的移动过程画出来。

因为要把鼠标移动的过程画出来,就要一次性接收大量的数据。我们需要把接收数据的变量data改造成FIFO数据缓冲区,然后再对数据逐一解读,解读出鼠标的坐标变化,然后才能依据解读出来的坐标,把鼠标指针画在屏幕上。

下一天的教程我们将会完成这个内容。

责任编辑: 鲁达

1.内容基于多重复合算法人工智能语言模型创作,旨在以深度学习研究为目的传播信息知识,内容观点与本网站无关,反馈举报请
2.仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证;
3.本站属于非营利性站点无毒无广告,请读者放心使用!

“操作系统如何管理鼠标,win7操作系统支持的基本鼠标操作有,操作系统的五大管理功能,操作系统如何管理文件,操作系统五大管理功能,操作系统的管理功能具体有哪些?”边界阅读