编写操作系统之_第1页
编写操作系统之_第2页
编写操作系统之_第3页
编写操作系统之_第4页
编写操作系统之_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、编写操作系统之键盘交互的实现Version 0.01谢煜波总述一个操作系统必需要具有交互性。所谓交互性就是指人与计算机之间的一种交流,有两种最基本的交互设备,一是显示器,一是键盘。显示器是计算机用来与人进行交流的,计算机通过显示器来告诉人一些信息,而键盘是人用来与计算机进行交流的,人通过键盘将命令发送给计算机,计算机接受人通过键盘发来的命令,然后进行处理,最后将处理的结果通过显示器告诉人,这样就完成了一次最简单最基本的交互。在本篇中,笔才将从一个编写操作系统的角度去描述操作系统应当怎样处理键盘,让人可以通过键盘与计算机进行交互。在本篇中,我们同样将以pyos 做为我们的实验平台,在pyos 上

2、实验操作系统对键盘的控制,为了进行本次实验,笔者专门编写了一人非常简单的“推箱子”游戏,当pyos 启动后,你可以输入“game (回车)”命令,然后系统就会调入这个游戏,这时,你可以通过上下左右四个方向键进行游戏,游戏结束后,按“ESC ”键,可以返回系统内核。所有的这一切你都会从本篇中了解到去怎样实现它。在本篇中,pyos 实现了类似windows 的一个消息系统,换句话说,此处的pyos 是由消息驱动的,如果你能windows 的消息驱动很好奇,但又不知它是怎样实现的,那么,本篇中所介绍的pyos 的消息驱动或许能对你理解windows 的消息戏动有些许帮助:)本篇与前几篇实验报告是一脉

3、相承的,特别是同保护模式下中断编程一篇有较为紧密的相关性,你可以在我的主页上()找到它们,上面的内容对理解本篇会具有较大帮助。在pyos 的编写过程中,得到了许多朋友的大力支持与帮助,中国安天实验室的张栗炜老师指出了pyos 中存在的一些问题,并给出了怎样完全在windows 环境下进行pyos 开发的方法,哈尔滨工业大学的kylix ,sun 为本实现中曾经出现的奇怪现象提出了非常好的意见,极大的扩展了笔者的思路及眼界,pineapple ,lizhenguo 为本实验的调试花费了许多精力 还有许多朋友给我发来电子邮件及在QQ 上留言,帮助并支持笔者进行实验,无法一一列举,仅在此对上述关心p

4、yos 的朋友致以最真诚的谢意与问候!Ok ,言归正传,下面就让我们开始我们的实验,Lets Go!键盘驱动简介CPU 对外部设备的管理是通过中断程序进行的,键盘也是一种外部设备,因此,CPU 对键盘的管理也是通过中断进行的。当你击打键盘的时候,键盘控制器会向CPU 提出中断申请,CPU 响应此中断进行处理,这就完成了一次很简单与人之间通过键盘进行的交互。有关键盘的很详情的硬件控制说明,大家可以在纯C 论坛上找到一篇名为PS/2键盘控制的文章,这篇文章里非常详细描述了有关键盘的硬件控制。由于本文旨在从操作系统的角度描述操作系统怎样通过键盘与人进行交互,因此,并不打算详细而完整的描述对键盘控制器

5、的控制方法,如果你想了解对键盘的更多控制细节,比如设定键盘响应时间,重复键频率,键盘自检等,你会在PS/2键盘控制中找到所有的内容。这里,仅就pyos 所用到的一些细节进行简单的介绍,因为,pyos 是一个很简单的系统。从上面的描述中我们可以看到,键盘有许多属性比如说响应时间,重复频率等需要进行设置,不过比较幸运的是,在计算机被引导后,BIOS 已经将这一切为我们做好了,如果你不需要很特别的应用,使用BIOS 为我们设定的默认值对于pyos 这样的系统来说是足够了,因此,我很乐意在这里将BIOS 进行的设置称之为键盘初始化,由于BIOS 的运行是在操作系统运行之前进行的,因此,当操作系统被调入

6、内存并运行时键盘已经完成了初始化,这个时候键盘就处于等待用户输入的状态。在前面几篇中我们知道,键盘中断是连结在计算机内部8259A 中断控制器的IRQ1号线上,当有按键发生时键盘控制器将会在IRQ1号线上送出中断信号,8259A 中断控制器将此中断信号与其它外部设备通过其余的IRQ 线送来的中断信号进行判优、排队,最后,将此信息送给CPU 。CPU 在一条指令运行结束后,会查询一下是否有中断信号送来,如果此时发现有中断信号送来,就会通过此中断信号的中断向量在中断描述符表中查询应当使用哪一个中断处理程序。当找到中断处理程序后,CPU 将调用此中断处理程序进行中断处理,完成中断处理后,CPU 再返

7、回到原来被中断的程序处继续执行。有关8259A 的初始化,中断向量及中断向量表的初始化的问题在上一篇实验报告保护模式下的8259A 芯片编程及中断处理探究中已经详细描述过了,这里就不在多费口舌了。现在我们只需要知道,CPU 通过8259A 发送来的键盘中断的中断向量号,在中断向量表中调入了键盘中断程序进行键盘中断的处理。下面我们将集中精力,来看看键盘中断程序到底都完成了些什么事情。键盘中断程序概述键盘中断程序到底要完成些什么事儿,这完全不是固定的。不同的系统对它的各个功能模块所需要完成的工作有不同的划分,不过对于键盘中断程序,它所必须完成的任务就是要告诉系统键盘上到底什么键被按下了,这是通过读

8、取键盘控制器的一个端口完成的。键盘上的每一个键都有两个唯一的数值进行标志。为什么要用两个数值而不是一个数值呢?这是因为一个键可以被按下,也可以被释放。当一个键按下时,它们产生一个唯一的数值,当一个键被释放时,它也会产生一个唯一的数值,我们把这些数值都保存在一张表里面,到时候通过查表就可以知道是哪一个键被敲击,并且可以知道是它是被按下还是被释放了。这些数值在系统中被称为键盘扫描码,而这张供查询用的表就被称为键盘扫描码集。最早的键盘键数较少,而现在的键盘键数比以前多了不少,键盘键数的变化也引起了扫描码的变化,历史上产生过三种键盘扫描码集,分别标记为Set 1,Set 2,Set 3,它们并没有什么

9、本质的不同,而区别只在于:对于键盘上的同一个键,所带表的扫描码不一样罢了。现代键盘常常使用Set 2,但是为了兼容以前的老式键盘,BIOS 在启动的时候自动将键盘控制器设置为工作在Set 1模式下,因此键盘控制器会自动翻译由键盘数据线送来的扫描码,将它有Set 2中的码转换成Set 1中的码。因此,传给CPU 或说操作系统的就是Set 1中的扫描码了,当然我们完全可以给键盘控制器发送命令,让它不进行这样的转换,不过这仿佛没有什么必要。下面,我们就来看看Set 1中的键盘扫描码:Set 1 键盘扫描码 释放码- 键 键 按下码按下码0A 29 0C 0D 2B 0E 39 0F 3A 2A 1D

10、 E0,5B释放码-8A 89 8C 8D AB 8E B9 8F BA AA 9D键 按下码 释放码1A9AA B C D E F G H I J K L1E 30 2E 20 12 21 22 23 17 24 25 269E B0 AE A0 92 A1 A2 A3 97 A4 A5 A69 - = BKSP SPACE TAB CAPS L SHFTL CTRLL GUIINSERT E0,52 E0,D2HOME E0,47 E0,97PG UPEND PG DNE0,49 E0,C9E0,4F E0,CF E0,51 E0,D1DELETE E0,53 E0,D3U ARROW E

11、0,48 E0,C8L ARROW E0,4B E0,CB D ARROW E0,50 E0,D0R ARROW E0,4D E0,CD NUM45C5E0,DBM N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 832 31 18 19 10 13 1F 14 16 2F 11 2D 15 2C 0B 02 03 04 05 06 07 08 09B2 B1 98 99 19 93 9F 94 96 AF 91 AD 95 AC 8B 82 83 84 85 86 87 88 89L ALTR SHFTR CTRLR GUIR ALTAPPS ENTER

12、ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F1238 36 E0,1D E0,5C E0,38 E0,5D 1C 01 3B 3C 3D 3E 3F 40 41 42 43 44 57 58B8 B6KP / E0,35 E0,B5KP * KP - KP + KP ENKP . KP 0 KP 1 KP 2 KP 3 KP 4 KP 5 KP 6 KP 7 KP 8 KP 9 ; ' , . /37 4A 4E 53 52 4F 50 51 4B 4C 4D 47 48 49 1B 27 28 33 34 35B7 CA CE D3 D2 CF D

13、0 D1 CB CC CD C7 C8 C9 9B A7 A8 B3 B4 B5E0,9D E0,DC E0,B8 E0,DD 9C 81 BB BC BD BE BF C0 C1 C2 C3 C4 D7 D8E0,1C E0,9CPRNT E0,2A, E0,B7,SCRN E0,37 E0,AA SCROLL PAUSE46 E1,1D,45 E1,9D,C5C6当然,上面这张表并不完整,但是它包括了普通键盘上的绝大多数键,完整的Set 1扫描码集可以在前面提到的PS/2键盘控制这篇文章中找到。从上面我们可以看出每一个键的键盘扫描码都是不一样的,而且按下码与弹出码也是不一样的,而且它们只间

14、并没有什么规律可言。噢,这里所说的规律是只它们同它们所对应键的ASCII 码之间没有什么联系,并不是说其它联系也一点没有。看一下A ,S ,D ,F 这几个键的键盘扫描码值:1E ,1F ,20,21,再看一下A ,S ,D ,F 在键盘上的位置,呵呵,通过上面这张表,我们不难想像,远古的键盘上的键是怎样排列的。:P仔细再看看上面这张表,我们还能发现一些其它规律,比如,释放码都大于0x80,且均为:按下码 + 0x80,有些键的扫描码是多个字节,对于两字节的扫描码,第一字节均是E0。你也许还会发现其它更多的有意思的现象,不过,对于我们的实验来说,了解这些就足够了。这里你也许想问,为什么不直接用

15、ASCII 码,而要用单独的扫描码呢?我想这个问题一是由于扫描码对于键盘硬件更容易实现(从上面扫描码与键盘上键的排列方式之间的关系就可以看出);二是由于ASCII 码数量是有限的,而且不能更改,但键盘上的键的个数却是不定的,随着键盘的发展,键可能增加也可能减少;第三,比如说“Alt ”键,在键盘上就有左右两个,也许以后我们可能在程序中会实现“按左Alt ,完成A 功能”,“按右Alt ,完成B 功能”的任务,如果使用ASCII 码,左右Alt 都会使CPU 收到同一个ASCII 码,CPU 也就无法分辩到底是“左Alt ”还是“右Al ”t 产生的了。呵呵,言归正转,继续我们的描述。当键盘按下

16、一个键或释放一个键的时候,键盘控制器都会把这个键的相应的扫描码值放在0x60这个端口寄存器中,并向CPU 提出中断请求,于是中断请求的主要任务就是读取0x60端口的键盘扫描码值,而操作系统通过中断服务程序读得的这个扫描码值,就能知道是哪个键被按下了,于是就可以进行相应的处理,完成与用户的交互了。0x60端口只有一个字节大小,而在上面的扫描码中我们可以发现有些键的扫描码是多个字节的。事实上,对于这种多个字节的扫描码,键盘控制器会向CPU 发出多个中断请求,并依次发送它们。比如说,Insert 键的按下码是“E0 52”这两个字节,那么当Insert 键被按下时,键盘控制器先把“E0”送到0x60

17、端口,然后申请中断,等待中断服务程序来读取。当中断服务程序读取之后,键盘控制器会立即把第二个字节“52”送到0x60端口,再一次申请中断,让中断服务程序来读取。注意这样一个事实:只有在中断服务程序取走了0x60端口的数据之后,键盘控制器才会向0x60端口送入新的数据,才会申请新的中断。有关中断服务程序的原理概述,描述到这里也就算描述完了,是不是非常的简单?多说无宜,百闻不如一见,下面我们将用一个实际的例子来看看倒底应当怎么去编程实现,有很多细节是说不清楚的,只有在代码中才可以窥见。下面就让我们用pyos 来进行这个实验,完成一个能接收用户键盘输入的操作系统:)。编写能接收键盘输入的pyos我们

18、先来简单看看pyos 的内核,也就是系统将pyos 调入内存中后,pyos 都干了些什么。下面就是pyos 的内核核心代码。const int KernelMessageMaxLength = 32 ; / 设定消息队列长度/* 定义一个消息队列所用的缓冲区 */struct_pyos_Message KernelMessage KernelMessageMaxLength ; class_template_pyos_Buffer< struct_pyos_Message > KernelMessageQueue ; /* 指向当前接收消息的队列的指针 */class_templa

19、te_pyos_Buffer< struct_pyos_Message >* ReceiveMessageQueue ;/* 定义暂存用户输入的缓冲区 */ char buffer 4 ; int buffer_count = 0 ;/* 内核主函数 */extern "C" void Pyos_Main( /* 系统初始化 */class_pyos_System:Init( ; /* 清屏,打印欢迎信息 */class_pyos_Video:ClearScreen( ;class_pyos_Video:PrintMessage( "Welcome t

20、o pyos, you can input " ;class_pyos_Video:PrintMessage( "game" , clRed , true , clBlue ; class_pyos_Video:PrintMessage( " to play a game:n" ; class_pyos_Video:PrintMessage( "pyos>" ;/* 初始化 Kernel 所用的消息队列,也是全局中必须存在的一个消息队列 */ KernelMessageQueue.Init( KernelMessage

21、 , KernelMessageMaxLength ;/* 定义 Kernel 的消息队列为当前消息接收队列,以接受键盘中断发来的消息 */ ReceiveMessageQueue = &KernelMessageQueue ;/* 现在可以许可键盘中断了 */class_pyos_Keyboard:Init( ; / 键盘类初始化class_pyos_Keyboard:OpenInterrupt( ; / 打开键盘中断/* 下面进入消息循环 */ struct_pyos_Message message ;bool ExitMessageLoop = false ;while ( !E

22、xitMessageLoop /* 从消息队列中取出消息,ReadData 返回值表示所取得的消息个数,如果是 0 ,则表示未取到消息 */if ( KernelMessageQueue.ReadData( message if ( message.MessageType = pyos_message_type_Keyboard / 键盘消息/ 从消息中取得扫描码,并调用翻译函数翻译此扫描码,取得ascii码char ch = class_pyos_Keyboard:TraslateScanCodeToAsciiCode( message.KeyboardScanCode ;/* 如果返回是

23、0 ,表示这是一个功能键 */if ( !class_pyos_Keyboard:StateKey.Down | ch = 0 / 忽略释放键、功能键的扫描码 continue ; else if ( ch = 'n' / 表示表户输入的是回车/* 检查 buffer 是否是空 */if ( buffer 0 /* 检查输入是否是 “game” */if ( buffer 0 = 'g' && buffer 1 = 'a' && buffer 2 = 'm' && buffer 3

24、= 'e' / 调入游戏/* 初始化游戏,主要是初始化游戏的消息队列 */ GameInit( ;/* 定义游戏为当前接收消息的队列 */ ReceiveMessageQueue = &GameMessageQueue ;/* 调入游戏进行 */ game_push_box_main( ;/* 游戏退出,恢复自己为当前接收消息的队列 */ ReceiveMessageQueue = &KernelMessageQueue ;/* 清屏,打印信息 */ class_pyos_Video:ClearScreen( ;class_pyos_Video:PrintMes

25、sage( "GameOver:Pn" ;else /* 输出错误信息 */ class_pyos_Video:PrintMessage( "nyour input is not a command :(" , clBrown ; /* 因为是回车键,所以清空用户的输入缓冲区 */for ( int i = 0 ; i < 4 ; +i buffer i = 0 ; buffer_count = 0 ;/* 显示新的提示符 */ class_pyos_Video:PrintMessage( "n" ; class_pyos_Vi

26、deo:PrintMessage( "pyos>" ; else /* 如是可打印字符则直接打印 */if ( ch>= 32 && ch <= 126 buffer buffer_count+ % 4 = ch ; class_pyos_Video:PrintMessage( ch ; _asm_( "hlt" ; / 停机,释放cpu的占用率 代码虽然长了一些,但是逻辑上非常清楚,是比较易读的。我们这就来一步步的看看。 首先进入Pyos_Main( 函数之后,系统调用了class_pyos_System:Init(

27、; 来进行内核的初始化,它完成了全局描述符表及中断向量表的初始化工作,这部份工作已经再前几篇实验报告中有详细描述,这里就不在多说了,你可以看看它的源代码以了解它们都完成了什么任务。内核初始化完成以后,系统调用了class_pyos_Video:PrintMessage( 打印一些欢迎信息,之后,系统为内核建立了一个消息队列,并定义了一个指向当前接受消息的消息队列的指针,使它指向系统的消息队列,以表明当前是由系统内核的消息队列接受消息,这是由 /* 初始化 Kernel 所用的消息队列,也是全局中必须存在的一个消息队列 */ KernelMessageQueue.Init( KernelMess

28、age , KernelMessageMaxLength ;/* 定义 Kernel 的消息队列为当前消息接收队列,以接受键盘中断发来的消息 */ReceiveMessageQueue = &KernelMessageQueue ;这两个语句完成的。对于消息队列,由于是在此实验中新实现的,故我下面将详细介绍一下。这个实验的pyos 是采用的消息驱动,简单来说,就是系统完成初始化工作之后就进入一个消息循环,然后不停的在探险测消息循环中是否有消息在存,如果有消息则取出。消息是一个结构体,它有一个成员被用着标志消息类别,另外一些成员被用着消息的参数,消息类别用来告诉消息的接受者这是一个什么消

29、息,消息的参数用来向消息的接收者传递数据。当应用程序取得消息后,则可以根据消息的类别进行一些处理。Pyos 的消息队列是用一个循队列实现的,这个循环队列的定义在buffer.h 文件中,它定义了两个最重要的函数,一个是PutData(,用于把消息放入队列,还有一个是GetData(用于从消息队列中取出消息。有关循环队列的原理及实现,任何一本讲数据结构的书上都有很详细的描述,大家对此想必也非常熟悉,这里就不详细论述了,有兴趣的朋友可以看看buffer.h 中的源代码,上面有很详细的注释。Pyos 的键盘中断程序主要工作就是从键盘控制器的0x60端口读取键盘扫描码,然后,它构造一条消息,让这个消息

30、的消息类型是键盘事件,让这个消息的参数是读到的键盘扫描码,然后把这条消息放入到内核的消息队列中,它的工作就完成了。当键盘中断程序把一条消息放入内核的消息队列中后,主程序在下一次循环中检测消息队列时就会发现消息队列中有消息,然后内核调用GetData ()函数取得消息,然后对此消息进行处理,这点在上面的代码中是非常清晰的。下面,我们将去看看本实验的核心内容,pyos 的键盘处理程序。Pyos 的键盘处理程序在上面的程序中我们可以看见,当内核进行消息循环之前,还执行了下面两条语句: class_pyos_Keyboard:Init( ; / 键盘类初始化class_pyos_Keyboard:Op

31、enInterrupt( ; / 打开键盘中断这两条语句的作用就在于初始化键盘中断,并打开键盘中断,即允许键盘向cpu 提出中断请求(在pyos 刚引导的时候,是屏蔽了所有中断的)。下面我们来看看这两个函数倒底完成了些什么工作,首先来看第一个函数: /* 初始化键盘类 */void class_pyos_Keyboard:Init( /* 初始化状态键 */StateKey.Down = false ;StateKey.AltDown = false ;StateKey.CtrlDown = false ;StateKey.ShiftDown = false ;/* 安装键盘中断,中断号为 0

32、x21 */class_pyos_Interrupt:InstallInterrupt( 0x21 , ( void * pyos_asm_interrupt_handle_for_keyboard ;/* 这里不许可键盘中断,因为有可能在许可键盘中断前主调用程序会准备一些其它资源,因此当主调用程序把资料 * 准备好之后,自行调用 OpenInterrupt 函数许可中断 */程序中的注释已经非常详尽了,需要另外说明的是pyos 用了一个StateKey 的结构体来保存键盘状态,比如说按下的是哪一个功能键,Shift ,Alt ,Ctrl 是否是被按下,这是一个按下键还是释放键等。在函数开头是

33、将各种状态设为初始值,之后,它调用了一个InstallInterrupt(函数来安装键盘中断。Pyos 的中断是通过安装方式进行的。在前几篇实验报告中我们已经知道操作统在内存中建立了一张中断向量表,为一个表项都存放着一个中断描述符,而每一个中断描述符都含有一个相应的中断处理函数的函数指针。当发生中断时就通过该中断的中断向量在这个中断向量表中取得相应的中断描述符,进而取得了相应的中断处理函数的函数指针,于是就可以调用中断处理程序进行中断处理。在pyos 最初初始化的时候,中断向量表是与class_pyos_Interrupt:Init(函数中建立的,当时系统并不知道会有哪些中断,以及它们的中断处

34、理函数的函数指针是什么,于是系统统一将每一个中断(cpu 共支持256个中断)的中断描述符都置成一个默认的中断描述符,而在需要的时候在由各个中断服务程序自行安装。所谓安装,其实就是用一个新的中断描述符去替换中断向量表中的旧的中断描述符,这就是InstallInterrupt(函数所完成的工作,当中断安装完成以后,系统只是更新了中断向量表中的相应表项,因此紧接着,系统调用了OpenInterrupt(函数来打开键盘中断,所谓打开中断,其实就是重新设置中断控制器8259A 的屏蔽寄存器,使之不再屏蔽键盘中断而矣,下面就是OpenInterrupt(函数的代码: /* 打开键盘中断 */void c

35、lass_pyos_Keyboard:OpenInterrupt( /* 许可键盘中断 */ class_pyos_System:ToPort( 0x21 , 0xfd ;非常简单,下面我想我们可以来看看我们最重的的一个部份,实际被cpu 所调用的中断处理函数: /* 中断实际处理函数 */void class_pyos_Keyboard:HandleInterrupt( / 从键盘控制器的0x60端口读入扫描码,否则键盘不会第二次中断,因为键盘在等待用户从0x60口读走数据unsigned char ch = class_pyos_System:FromPort( 0x60 ;/ 先过滤掉特

36、殊字节if ( ch = 0x0 / 0x0 表示按键产生错误return ; else if ( ch = 0xe0 / 检测是否是扩展码的前缀/ 设置 扩展码标记位ex = true ;/ 直接返回,等待下一个中断送来真实的扫描码return ; else / 构造一个键盘消息 struct_pyos_Message message ; message.MessageType = pyos_message_type_Keyboard ;if ( ex = true ex = 0 ; / 清空扩展码标志有了前面所介绍的背景,再来看这个函数,就非常简单了,因此,也就不在此处多费口舌了,直接进入

37、下一个环节。Pyos 对用户输入的处理其实写到这里,本篇所要描述的主要问题基本上是已经描述完成了,虽然还有一些小细节,比如pyos 是怎样识别及保存用户输入的。首先来看看pyos 是怎样识别用户输入的。当内核从消息队列中取得消息后,就从这个消息的参数中取得了扫描码,然后,系统调用了TranslateScanCodeToAsciiCode( 函数将这个扫描码翻译为Ascii 码,这其实就是一个查询Set 1表的过程,有兴趣的朋友可以看看它的源代码。如果所按下的是一个功能键,TranslateScanCodeToAsciiCode( 会返回 0 ,然后将功能键状态保存在StateKey 中,否则,

38、就返回这个键的Ascii 码。这样内核就识别出了用户的输入。对于pyos 是怎样保存用户输入的这个问题,在本实验中,pyos 用的是一种最简单最笨最烂最不具扩展性的方法:P ,pyos 定义了一个数组 buffer ,用于保存用户输入,我们估且称这个数组为用户输入缓冲区,它依次将用刻的输入放入缓冲区,然后当用户输入回车的时候,就检测buffer 中存的值是不是“game ”,如果是,则认为用户在输入“game ”会按下了回车,也即用户输入了“game ”命令,于是就调入游戏程序,如果不是则认为用户输入了一个不可识别的命令,于是输出一个错误信息,并清空了缓冲区,等待用户下一次输入。这里有个细节需要提一下,当调入游戏程序后,用户键盘消息就应当被游戏程序而不是内核接收了,于是此时,游戏程序的消息队列成为了当前接收消息的队列,因此,在正式调入游戏程序之前,系统还执行了下面两条语句: /* 初始化游戏,主要是初始化游戏的消息队列 */ GameInit( ; /* 定义游戏为当前接收消息的队列 */ReceiveMessageQueue = &GameMessageQueue ;由于游戏只是一个演示,而并不是我们实验的主角,因此对游戏是怎样实现的就不在此处详细描述了,但其所用的原理完全与本篇报告介绍的相同,源代

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论