一步步写操作系统之第五步:进一步完善域结构并根据域结构重新编写键盘驱动
此次,对域结构进行了进一步完善,除了“子域”的概念没有出来外,域结构的最基本特性已经展现出来了。下面就对“域”的一些特点进行一下简单总结。然后利用“域”来重新实现键盘驱动程序。一个域,包含以下几个基本要素:
1.生命值
2.(主动)动作函数 //action 函数
3.(被动)动作函数 //on 事件(函数)
4.子域 //未实现
域结构的操作(相当于域结构的系统调用函数):
1.运行域结构 //yu.c 中的run()函数
(1)执行动作双向循环链表中的一个动作
(2)执行.(被动)动作函数(on事件)列表里的所有函数
(3)指向下一个(主动)动作
2.加载(主动)动作函数 //向动作双向循环链表添加一个动作,见yu.c 中的AddAction(struct action_s *newAction)函数
3.移除(主动)动作函数 //从动作双向循环链表移除一个动作,见yu.c 中的DelAction(struct action_s *delAction)函数
4.注册一个on 事件 //可重复性的向on事件列表添加函数(p.s:(主动)动作函数具有唯一性)
域结构运行特点:
动作周期:执行一遍run()函数,形成一个动作周期,在这个过程里,只有一个(主动)动作和以及执行此周期前的所有on 事件被执行,在此过程中,向on事件列表添加的函数,会在下一个动作周期执行。
域周期:动作双向循环链表中所有的(主动)动作都被执行了一遍,形成一个域周期,在一个域周期内一个(主动)动作最多执行一遍,若在一个域周期内添加了新的(主动)动作,将会在周期结束时,或者说下各个域周期开始时被执行(若没有在此域周期内又被移除掉的话)。
之所以要花费精力来将“域”的情况进行如上总结,是因为我以后将会完全利用域结构来实现这个操作系统,若不理解域的特性,就无法理解程序的内在逻辑。
此次实现键盘驱动,我将键盘的字符输入功能和键盘作为控制器的控制功能分离开来,利用域结构的结构特点分别实现。主要实现的是将所有可显示字符的提取部分,控制部分,根据当前需要简单实现了几个。其他的控制功能,可以随时随意的添加,而不会对以实现部分有什么影响。
为了便于理解,先使用“域语言”伪代码描述一遍:
程序代码:
键盘域: 数据: 生命值:int kb_life = 0; shift状态:t_bool shift; CapsLock状态:t_bool capsLock; NumLock状态:t_bool numLock; 0xE0扫描码:t_bool on0xE0Flag; 0xE1扫描码:t_bool on0xE1Flag; 键码双缓冲池:struct keyBuf_s keyBuf[2];等…… //为了减少对键盘中断的影响,建立了一个双缓冲池结构,轮流提供给键盘中断保存键码 键码字符映射表:t_32 keymap[NR_SCAN_CODES * 2];//用于将扫描码转换为相应字符 按键动作映射表:struct on_s *keyOntable[0x100];//用于动态实现某个按钮的控制性功能 主动函数: 键码转字符:void ScanCodeToCharFun(); //读取键码缓冲池里的扫描码,提取与转换成对应的字符 { 交换键码双缓冲池,若缓冲池中无记录,退出函数。 循环提取缓冲池中的扫描码: 从缓冲池取得扫描码。 若按下shift,从键码字符映射表的第二列中获取对应的字符,否则从第一列获取。 若CapsLock键被按下且是字母,将大小写互换, (否则)若扫描码是小键盘区的且NumLock键按下,重新获取在第二列中获取对应的字符。 若获取的字符值为零,跳入下一循环。 已经取得字符了,根据需要处理吧,这里就简单打印出来。 } 被动函数: 键盘中断处理:void OnKeyEvent(); //这个是一个特殊的(被动)动作函数,它是由操作系统外部中断调用,与域的on事件区别在于,在任何时候都有可能发生,所以要编写得尽可能简练。 { 取得扫描码。 根据扫描码,查找按键动作映射表中对应的被动函数,注册到on事件列表上。 若键码转字符动作被禁止,或是中断码,不进行进一步处理,退出函数 若缓冲池未满,将扫描码记录到缓冲池 } Shift按下:void OnShiftDownFun(); { 标记Shift被按下,注册自身Shift松开 } Shift松开:void OnShiftUpFun() { 标记Shift松开,注册Shift按下 } CapsLock点击:void OnCapsLockFun() { 置反CapsLock状态值,重新注册自身 } NumLock点击:void OnNumLockFun() { 置反NumLock状态值,重新注册自身 } …… …… 当键码转字符执行时,生命值长,若生命值过大,生命值归零,注销键码转字符动作。 当生命值为零时,若键盘中断处理执行时,加载键码转字符动作,生命值设为一。
除了键盘驱动程序以外,此次,还对显示器(视频)的端口进行了简单的操控,实现上下移动显示区域,以防止屏幕显示超出时,看不到新新的显示内容。
在下一步里,将进一步完善它,并争取实现一个简单的tty。
下面是此次新添加或有过修改的代码。
在print.c中添加了一个换行函数,函数代码如下
程序代码:
void disp_next()//换行 { asm{ mov eax, disp_pos //求出下一行起始位置坐标 mov bl, 160 div bl and eax, 0FFh inc eax mov bl, 160 mul bl mov disp_pos, eax } }
code:kernel.c(改)
程序代码:
//文件:kernel.c //功能:内核程序,先初始化各个模块驱动,然后循环调用域执行函数,运行域结构 //运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。 //作者:miao //时间:2010-5-30 #define YCBIT 32 //告诉编译器,以32位格式编译程序 #define YCORG 0x0 //此值会对在编译时对变量函数等产生地址基址偏移量,简单起便,设置为0 #include "global.h" #include "kernel.h" #include "print.h" #include "klib.h" #include "i8259.h" #include "yu.h" #include "console.h"//要在keyboard.h之前,因为keyboard.h里用到了console.h的一些变量 #include "keyboard.h" void init(); //内核入口点 asm void main() { lgdt cs:GdtPtr //加载新的GDTR mov eax, SelectorVideo mov gs, ax //视频段选择子(目的) mov eax, SelectorData32 //令32位代码段的变量(printPlace)可以读写 mov ds, ax call init //初始化函数 sti //开中断 jmp kernel_main } void init() { disp_str("================ init start =================\n"); disp_str(" init idt -------------------------------- "); init_prot(); //初始化IDT disp_str("ok\n"); disp_str(" init keyboard --------------------------- "); init_keyboard();//初始化键盘 disp_str("ok\n"); disp_str(" init yu\n"); life = 100;//初始化根域生命值 disp_str("----- init action ------------------------ "); AddAction(&nullAction);//测试action函数用,模拟光标的功能 disp_str("ok\n"); disp_str("----- init on ---------------------------- "); on_list.idx = 0; on_list.total = 0; on_list.flag = 1; AddOn(&nullOn2);//测试on事件用,打印一个等边三角形 disp_str("ok\n"); disp_str("================ init end ===================\n"); } int kernel_main() { while(life) { Run(); } disp_str("================ yu end =====================\n"); disp_str("died"); while(1); return 0; } #include "print.c" #include "klib.c" #include "i8259.c" #include "yu.c" #include "keyboard.c" #include "console.c"
code:yu.h(改)
程序代码:
//文件:yu.h //功能:yu头文件,域结构需要用到的公共函数的声明等 //作者:miao //时间:2010-5-30 #define NULL 0 #define NAME_MAX 32 typedef void (*action_fun)(); typedef void (*on_fun)(); //根域生命值(为零,退出域动作链表循环) int life = 0; //动作结构 struct action_s { char name[NAME_MAX]; //动作名称 action_fun run; //动作调用的函数 struct action_s *last; //上一动作 struct action_s *next; //下一动作 }; //动作链表 struct actionList_s { unsigned int count; //动作计数器 struct action_s *seek; //当前动作 }actionList = {0,NULL}; //添加一个动作到动作链表表里 void AddAction(struct action_s *newAction); //从动作链表里删除一个动作 void DelAction(struct action_s *delAction); void Run(); //执行当前动作 void NullActionFun();//空动作,限制链表执行速度或将来用于管理动作链表 struct action_s nullAction = {"NullFun",&NullActionFun,NULL,NULL}; //on事件结构 struct on_s { char name[NAME_MAX]; //on事件名称 on_fun run; //on调用的函数 struct on_s *next; //下一个on事件,暂时没有特别用处 char state; //保留,暂时没有特别用处 }; #define ON_LIST_MAX 100 //on事件表结构,双向向内增长堆栈 struct on_list_s { struct on_s *list[ON_LIST_MAX]; //on事件堆栈(on事件可以重复) int idx; //指向lish空的地方 int total; //堆栈中on事件的总数 t_bool flag; //增长标记 }on_list; //添加一个on事件到on队列(在on队列中on事件可重复添加) void AddOn(struct on_s *newOn); void NullOnFun1();//空on事件1 struct on_s nullOn1 = {"NullOn1",&NullOnFun1,NULL,1}; void NullOnFun2();//空on事件2 struct on_s nullOn2 = {"NullOn2",&NullOnFun2,NULL,2};
code:yu.c(改)
程序代码:
//文件:yu.c //功能:域结构,管理一个动作双向链表,循环执行链表上的动作函数 //作者:miao //时间:2010-5-30 //添加一个动作到动作链表里 void AddAction(struct action_s *newAction) { disp_color_str("add:",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); disp_color_str((*newAction).name,MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); if((*newAction).next != NULL) { disp_color_str("**add fail!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); return; } if(actionList.count == 0)//若链表里没有元素 { actionList.seek = newAction; (*newAction).next = newAction; (*newAction).last = newAction; } else//向动链表表添加一个动作到seek动作指针前 { (*newAction).last = (*actionList.seek).last; (*newAction).next = actionList.seek; (*(*actionList.seek).last).next = newAction; (*actionList.seek).last = newAction; } actionList.count++; } //从动作链表里删除一个动作 void DelAction(struct action_s *delAction) { disp_color_str(" del:",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); disp_color_str((*delAction).name,MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); //disp_int(actionList.count); if((*delAction).next == NULL) { disp_color_str("**del fail!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); return; } if(actionList.count == 0) return;//若链表里没有元素 if(actionList.count == 1) actionList.seek = NULL; else //将此动作从链表里移除 { (*(*delAction).last).next =(*delAction).next; (*(*delAction).next).last =(*delAction).last; actionList.seek = (*delAction).last; } (*delAction).next = NULL; (*delAction).last = NULL; actionList.count--; } //添加一个on函数到on队列 void AddOn(struct on_s *newOn) { //disp_str("AddOn\n"); if(on_list.total == ON_LIST_MAX) { disp_color_str("**on list full!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); return; } on_list.list[on_list.idx] = newOn; on_list.idx += on_list.flag; on_list.total++; } int on_idx; void Run() { //执行当前动作 if(actionList.seek != NULL) { (*actionList.seek).run(); } //处理on事件的控制结构 on_idx = on_list.idx; asm{cli} on_list.flag = -on_list.flag;//改变堆栈增长方向 on_list.total=(on_list.idx+ON_LIST_MAX)%ON_LIST_MAX; on_list.idx=(on_list.flag == 1) ? 0 : ON_LIST_MAX -1; asm{sti} //一次性的执行on堆栈中的on事件 for(int i = ((on_list.flag == 1)?ON_LIST_MAX -1:0); i != on_idx; i-=on_list.flag) { (*on_list.list[i]).run(); } //指向下一个动作 if(actionList.seek != NULL) actionList.seek = (*actionList.seek).next; } void sleep(int i); //使用下面两个on函数打印一个等边三角形 //空on函数1 int testCount = 11;//testCount-2 == 等边三角形边长 void NullOnFun1() { if(!testCount) //停止存活 return; disp_str("* "); AddOn(&nullOn1);//存活 } //空on函数2 void NullOnFun2() { if(testCount <= 0) //停止存活 return; disp_next(); for(int i=0;i<testCount;i++) disp_str(" "); AddOn(&nullOn2);//存活 AddOn(&nullOn1);//繁殖 testCount--; } //空动作,限制链表执行速度或将来用于管理动作链表 void NullActionFun() { disp_color_str(" ",MAKE_COLOR(WHITE,RED)| BRIGHT | FLASH); disp_pos-=2; sleep(100); disp_color_str(" ",MAKE_COLOR(BLUE,RED)); disp_pos-=2; sleep(50); } void sleep(int i) { while(i--) for(int i=0;i<100;i++) for(int j=0;j<100;j++); }
code:keyboard.h(改)
程序代码:
//文件:keyboard.h //功能:keyboard头文件,内核需要用到的公共函数的声明等 //作者:miao //时间:2010-5-30 //AT(大口)键盘 8042端口 //键盘数据端口 读:读取输出缓冲器 写:写入输入缓冲器(8042 Data&8048 Command) #define KB_DATA 0x60 //键盘命令端口 读:读取状态寄存器 写:写入输入缓冲器(8042 Command) #define KB_CMD 0x64 #define LED_CODE 0xED #define KB_ACK 0xFA #define NR_SCAN_CODES 0x54 //扫描码的数目(keymap的行数)除去最后面的不可显示字符的部分 t_32 keymap[NR_SCAN_CODES * 2] = { //shift未按下 shift按下 扫描码 //!Shift Shift scan code 0, 0, //0x00 - none 0, 0, //0x01 - ESC '1', '!', //0x02 - '1' '2', '@', //0x03 - '2' '3', '#', //0x04 - '3' '4', '$', //0x05 - '4' '5', '%', //0x06 - '5' '6', '^', //0x07 - '6' '7', '&', //0x08 - '7' '8', '*', //0x09 - '8' '9', '(', //0x0A - '9' '0', ')', //0x0B - '0' '-', '_', //0x0C - '-' '=', '+', //0x0D - '=' 0, 0, //0x0E - BS 0, 0, //0x0F - TAB 'q', 'Q', //0x10 - 'q' 'w', 'W', //0x11 - 'w' 'e', 'E', //0x12 - 'e' 'r', 'R', //0x13 - 'r' 't', 'T', //0x14 - 't' 'y', 'Y', //0x15 - 'y' 'u', 'U', //0x16 - 'u' 'i', 'I', //0x17 - 'i' 'o', 'O', //0x18 - 'o' 'p', 'P', //0x19 - 'p' '[', '{', //0x1A - '[' ']', '}', //0x1B - ']' 0, 0, //0x1C - CR/LF 0, 0, //0x1D - l. Ctrl 'a', 'A', //0x1E - 'a' 's', 'S', //0x1F - 's' 'd', 'D', //0x20 - 'd' 'f', 'F', //0x21 - 'f' 'g', 'G', //0x22 - 'g' 'h', 'H', //0x23 - 'h' 'j', 'J', //0x24 - 'j' 'k', 'K', //0x25 - 'k' 'l', 'L', //0x26 - 'l' ';', ':', //0x27 - ';' '\'', '"', //0x28 - '\'' '`', '~', //0x29 - '`' 0, 0, //0x2A - l. SHIFT '\\', '|', //0x2B - '\' 'z', 'Z', //0x2C - 'z' 'x', 'X', //0x2D - 'x' 'c', 'C', //0x2E - 'c' 'v', 'V', //0x2F - 'v' 'b', 'B', //0x30 - 'b' 'n', 'N', //0x31 - 'n' 'm', 'M', //0x32 - 'm' ',', '<', //0x33 - ',' '.', '>', //0x34 - '.' '/', '?', //0x35 - '/' 0, 0, //0x36 - r. SHIFT '*', '*', //0x37 - '*' 0, 0, //0x38 - ALT ' ', ' ', //0x39 - ' ' 0, 0, //0x3A - CapsLock 0, 0, //0x3B - F1 0, 0, //0x3C - F2 0, 0, //0x3D - F3 0, 0, //0x3E - F4 0, 0, //0x3F - F5 0, 0, //0x40 - F6 0, 0, //0x41 - F7 0, 0, //0x42 - F8 0, 0, //0x43 - F9 0, 0, //0x44 - F10 0, 0, //0x45 - NumLock 0, 0, //0x46 - ScrLock 0, '7', //0x47 - Home 0, '8', //0x48 - CurUp 0, '9', //0x49 - PgUp 0, '-', //0x4A - '-' 0, '4', //0x4B - Left 0, '5', //0x4C - MID 0, '6', //0x4D - Right 0, '+', //0x4E - '+' 0, '1', //0x4F - End 0, '2', //0x50 - Down 0, '3', //0x51 - PgDown 0, '0', //0x52 - Insert 0, '.', //0x53 - Delete }; #define KEY_BUF_MAX 32 //键盘输入缓冲区大小 struct keyBuf_s { int idx; //缓冲区中共有多少字节 char buf[KEY_BUF_MAX]; //缓冲区 }; void OnKeyEvent(); //键盘中断处理函数 //键盘服务系统相关 int kb_life = 0; struct keyBuf_s keyBuf[2]; //为了减少对键盘中断的影响,采用双缓冲方式 struct keyBuf_s *busyKeyBuf=&keyBuf[0];//指向键盘中断正在使用的缓冲区 struct keyBuf_s *freeKeyBuf=&keyBuf[1];//指向空闲(待处理)的缓冲区 struct keyBuf_s *keyBufPoint = busyKeyBuf;//键盘中断使用这个缓冲区 t_bool shift; // shift 状态 t_bool capsLock; // Caps Lock 状态 t_bool numLock; // Num Lock 状态 t_bool on0xE0Flag; // 收到0xE0扫描码 t_bool on0xE1Flag; // 收到0xE1扫描码 void init_keyboard();//初始化键盘 void ScanCodeToCharFun();//键码转字符动作函数 struct action_s scanCodeToChar = {"scanCodeToChar",&ScanCodeToCharFun,NULL,NULL}; //和字符处理结合的键盘事件 void OnShiftDownFun(); struct on_s onShiftDown = {"onShiftDown",&OnShiftDownFun,NULL,NULL}; void OnShiftUpFun(); struct on_s onShiftUp = {"onShiftUp",&OnShiftUpFun,NULL,NULL}; void OnCapsLockFun(); struct on_s onCapsLock = {"OnLineDown",&OnCapsLockFun,NULL,NULL}; void OnNumLockFun(); struct on_s onNumLock = {"OnPageUp",&OnNumLockFun,NULL,NULL}; //若碰到E0和E1组合的功能键必须处理,否则可显示字符处理程序会被锁住 void On0xE0Fun(); struct on_s on0xE0 = {"On0xE0",&On0xE0Fun,NULL,NULL}; void On0xE1Fun(); struct on_s on0xE1 = {"On0xE1",&On0xE1Fun,NULL,NULL}; //为所有扫描码或中断码建立一个on事件指针表,根据需要动态管理此表来实现键盘控制功能 struct on_s *keyOntable[0x100] = { //前 0x80个都是扫描码(键盘按下) NULL, //0x00 - none NULL, //0x01 - ESC NULL, //0x02 - '1' NULL, //0x03 - '2' NULL, //0x04 - '3' NULL, //0x05 - '4' NULL, //0x06 - '5' NULL, //0x07 - '6' NULL, //0x08 - '7' NULL, //0x09 - '8' NULL, //0x0A - '9' NULL, //0x0B - '0' NULL, //0x0C - '-' NULL, //0x0D - '=' NULL, //0x0E - BS NULL, //0x0F - TAB NULL, //0x10 - 'q' NULL, //0x11 - 'w' NULL, //0x12 - 'e' NULL, //0x13 - 'r' NULL, //0x14 - 't' NULL, //0x15 - 'y' NULL, //0x16 - 'u' NULL, //0x17 - 'i' NULL, //0x18 - 'o' NULL, //0x19 - 'p' NULL, //0x1A - '[' NULL, //0x1B - ']' NULL, //0x1C - CR/LF NULL, //0x1D - l. Ctrl NULL, //0x1E - 'a' NULL, //0x1F - 's' NULL, //0x20 - 'd' NULL, //0x21 - 'f' NULL, //0x22 - 'g' NULL, //0x23 - 'h' NULL, //0x24 - 'j' NULL, //0x25 - 'k' NULL, //0x26 - 'l' NULL, //0x27 - ';' NULL, //0x28 - '\'' NULL, //0x29 - '`' &onShiftDown, //0x2A - l. SHIFT NULL, //0x2B - '\' NULL, //0x2C - 'z' NULL, //0x2D - 'x' NULL, //0x2E - 'c' NULL, //0x2F - 'v' NULL, //0x30 - 'b' NULL, //0x31 - 'n' NULL, //0x32 - 'm' NULL, //0x33 - ',' NULL, //0x34 - '.' NULL, //0x35 - '/' &onShiftDown, //0x36 - r. SHIFT NULL, //0x37 - '*' NULL, //0x38 - ALT NULL, //0x39 - ' ' &onCapsLock, //0x3A - CapsLock NULL, //0x3B - F1 NULL, //0x3C - F2 NULL, //0x3D - F3 NULL, //0x3E - F4 NULL, //0x3F - F5 NULL, //0x40 - F6 NULL, //0x41 - F7 NULL, //0x42 - F8 NULL, //0x43 - F9 NULL, //0x44 - F10 &onNumLock, //0x45 - NumLock NULL, //0x46 - ScrLock NULL, //0x47 - Home &onLineUp, //0x48 - CurUp &onPageUp, //0x49 - PgUp NULL, //0x4A - '-' NULL, //0x4B - Left NULL, //0x4C - MID NULL, //0x4D - Right NULL, //0x4E - '+' NULL, //0x4F - End &onLineDown, //0x50 - Down &onPageDown, //0x51 - PgDown NULL, //0x52 - Insert NULL, //0x53 - Delete NULL, //0x54 - Enter NULL, //0x55 - ??? NULL, //0x56 - ??? NULL, //0x57 - F11 NULL, //0x58 - F12 NULL, //0x59 - ??? NULL, //0x5A - ??? NULL, //0x5B - ??? NULL, //0x5C - ??? NULL, //0x5D - ??? NULL, //0x5E - ??? NULL, //0x5F - ??? NULL, //0x60 - ??? NULL, //0x61 - ??? NULL, //0x62 - ??? NULL, //0x63 - ??? NULL, //0x64 - ??? NULL, //0x65 - ??? NULL, //0x66 - ??? NULL, //0x67 - ??? NULL, //0x68 - ??? NULL, //0x69 - ??? NULL, //0x6A - ??? NULL, //0x6B - ??? NULL, //0x6C - ??? NULL, //0x6D - ??? NULL, //0x6E - ??? NULL, //0x6F - ??? NULL, //0x70 - ??? NULL, //0x71 - ??? NULL, //0x72 - ??? NULL, //0x73 - ??? NULL, //0x74 - ??? NULL, //0x75 - ??? NULL, //0x76 - ??? NULL, //0x77 - ??? NULL, //0x78 - ??? NULL, //0x79 - ??? NULL, //0x7A - ??? NULL, //0x7B - ??? NULL, //0x7C - ??? NULL, //0x7D - ??? NULL, //0x7E - ??? NULL, //0x7F - ??? //后面 0x80个都是中断码(键盘按键放开) NULL, //0x80 - none NULL, //0x81 - ESC NULL, //0x82 - '1' NULL, //0x83 - '2' NULL, //0x84 - '3' NULL, //0x85 - '4' NULL, //0x86 - '5' NULL, //0x87 - '6' NULL, //0x88 - '7' NULL, //0x89 - '8' NULL, //0x8A - '9' NULL, //0x8B - '0' NULL, //0x8C - '-' NULL, //0x8D - '=' NULL, //0x8E - BS NULL, //0x8F - TAB NULL, //0x90 - 'q' NULL, //0x91 - 'w' NULL, //0x92 - 'e' NULL, //0x93 - 'r' NULL, //0x94 - 't' NULL, //0x95 - 'y' NULL, //0x96 - 'u' NULL, //0x97 - 'i' NULL, //0x98 - 'o' NULL, //0x99 - 'p' NULL, //0x9A - '[' NULL, //0x9B - ']' NULL, //0x9C - CR/LF NULL, //0x9D - l. Ctrl NULL, //0x9E - 'a' NULL, //0x9F - 's' NULL, //0xA0 - 'd' NULL, //0xA1 - 'f' NULL, //0xA2 - 'g' NULL, //0xA3 - 'r' NULL, //0xA4 - 'j' NULL, //0xA5 - 'k' NULL, //0xA6 - 'l' NULL, //0xA7 - ';' NULL, //0xA8 - '\'' NULL, //0xA9 - '`' &onShiftUp, //0xAA - l. SHIFT NULL, //0xAB - '\' NULL, //0xAC - 'z' NULL, //0xAD - 'x' NULL, //0xAE - 'c' NULL, //0xAF - 'v' NULL, //0xB0 - 'b' NULL, //0xB1 - 'n' NULL, //0xB2 - 'm' NULL, //0xB3 - ',' NULL, //0xB4 - '.' NULL, //0xB5 - '/' &onShiftUp, //0xB6 - r. SHIFT NULL, //0xB7 - '*' NULL, //0xB8 - ALT NULL, //0xB9 - ' ' NULL, //0xBA - CapsLock NULL, //0xBB - F1 NULL, //0xBC - F2 NULL, //0xBD - F3 NULL, //0xBE - F4 NULL, //0xBF - F5 NULL, //0xC0 - F6 NULL, //0xC1 - F7 NULL, //0xC2 - F8 NULL, //0xC3 - F9 NULL, //0xC4 - F10 NULL, //0xC5 - NumLock NULL, //0xC6 - ScrLock NULL, //0xC7 - Home NULL, //0xC8 - CurUp NULL, //0xC9 - PgUp NULL, //0xCA - '-' NULL, //0xCB - Left NULL, //0xCC - MID NULL, //0xCD - Right NULL, //0xCE - '+' NULL, //0xCF - End &on0xE0, //0xE0 - Down &on0xE1, //0xE1 - PgDown NULL, //0xE2 - Insert NULL, //0xE3 - Delete NULL, //0xE4 - Enter NULL, //0xE5 - ??? NULL, //0xE6 - ??? NULL, //0xE7 - F11 NULL, //0xE8 - F12 NULL, //0xE9 - ??? NULL, //0xEA - ??? NULL, //0xEB - ??? NULL, //0xEC - ??? NULL, //0xED - ??? NULL, //0xEE - ??? NULL, //0xEF - ??? NULL, //0xF0 - ??? NULL, //0xF1 - ??? NULL, //0xF2 - ??? NULL, //0xF3 - ??? NULL, //0xF4 - ??? NULL, //0xF5 - ??? NULL, //0xF6 - ??? NULL, //0xF7 - ??? NULL, //0xF8 - ??? NULL, //0xF9 - ??? NULL, //0xFA - ??? NULL, //0xFB - ??? NULL, //0xFC - ??? NULL, //0xFD - ??? NULL, //0xFE - ??? NULL, //0xFF - ??? NULL, //0xF0 - ??? NULL, //0xF1 - ??? NULL, //0xF2 - ??? NULL, //0xF3 - ??? NULL, //0xF4 - ??? NULL, //0xF5 - ??? NULL, //0xF6 - ??? NULL, //0xF7 - ??? NULL, //0xF8 - ??? NULL, //0xF9 - ??? NULL, //0xFA - ??? NULL, //0xFB - ??? NULL, //0xFC - ??? NULL, //0xFD - ??? NULL, //0xFE - ??? NULL, //0xFF - ??? };
code:keyboard.c(改)
程序代码:
//文件:keyboard.c //功能:初始化键盘、以及设置中断相关的函数 //作者:miao //时间:2010-5-30 //键盘中断处理函数 void OnKeyEvent() { t_8 scan_code = in_byte(KB_DATA); //获取扫描码 //disp_int(scan_code); //disp_str(" "); //return; //处理属于控制性质的按键扫描码 struct on_s *keyOnPoin = keyOntable[scan_code]; if(keyOnPoin != NULL) { AddOn(keyOnPoin); //加入On事件队列 keyOntable[scan_code]=NULL; } //处理属于字符扫描码 //键盘域生命值为负,表示不需要对字符扫描码,同时排除中断码 if(kb_life<0 || scan_code >= 0x80 )//|| on0xE0Flag || on0xE1Flag) return ; //在实现所有E0,E1的功能键时,需要过滤掉功能键对应的可显示字符 //将扫描法放入缓冲区 if(keyBufPoint->idx < KEY_BUF_MAX) //若缓冲区未满,记录信息 { keyBufPoint->buf[keyBufPoint->idx++] = scan_code; //记录扫描码 } else disp_color_str("**keyBuf full!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH); if(kb_life==0)//当键盘生命值为零,表示键盘字符处理动作不在执行链表里 { kb_life=1; AddAction(&scanCodeToChar);//加载键盘服务域 } } void InitKeyOnEvent(struct on_s *newOn, t_8 scan_code) { (*newOn).next = keyOntable[scan_code]; keyOntable[scan_code]=newOn; } void OnShiftDownFun() { if(shift==1) return; shift = 1; InitKeyOnEvent(onShiftUp,0xAA); return; } void OnShiftUpFun() { shift = 0; InitKeyOnEvent(onShiftDown,0x2A); return; } void OnCapsLockFun() { capsLock = !capsLock; InitKeyOnEvent(onCapsLock,0x3A); return; } void OnNumLockFun() { numLock = !numLock; InitKeyOnEvent(onNumLock,0x45); return; } void On0xE0Fun() { disp_str("On0xE0Fun "); on0xE0Flag = 1; return; } void On0xE1Fun() { disp_str("On0xE1Fun "); on0xE1Flag = 1; return; } //键盘中断初始化函数 void init_keyboard() { kb_life = 0;//键盘域的生命值 //初始化键盘缓冲区 keyBuf[0].idx=0; keyBuf[1].idx=0; busyKeyBuf=&keyBuf[0];//指向键盘中断正在使用的缓冲区 freeKeyBuf=&keyBuf[1];//指向空闲(待处理)的缓冲区 keyBufPoint = busyKeyBuf;//键盘中断使用这个缓冲区 //初始化键盘标记 capsLock = 0; numLock = 1; shift = 0; enable_irq(KEYBOARD_IRQ); //开键盘中断 } //将缓冲区里扫描码转换成相应的字符,然后进行后续处理 t_bool make; //TRUE:make FALSE:break t_32 *keyrow; //指向 keymap[] 的某一行 t_32 key = 0; //用一个整型来表示一个键。 char moutput[2]=" "; //键盘字符处理动作 void ScanCodeToCharFun() { //交换双缓冲区 asm{cli} keyBufPoint = freeKeyBuf; freeKeyBuf = busyKeyBuf; busyKeyBuf = keyBufPoint; asm{sti} if(freeKeyBuf->idx == 0) //若没有记录,不处理 { kb_life++; if(kb_life>=20)//当空闲次数多时,撤销键盘字符处理动作 { kb_life = 0; DelAction(&scanCodeToChar); } return; } //提取缓冲区中扫描码对应的可显示字符 for(int i = 0;i<freeKeyBuf->idx;i++) { make = freeKeyBuf->buf[i];//取得扫描码 //先定位到 keymap 中的行 keyrow = &keymap[make * 2]; if(shift)//根据是否按下shift,取不同的值 key = keyrow[1]; else key = keyrow[0]; //若 Caps Lock 键被按下 字符大小写要互换 if(capsLock && ((key >='a' && key<='z') || (key >='A'&& key<='Z'))) key^=0x20; //不是字母,若是小键盘区的扫描码且 Num Lock 按下,要显示小键盘的字符 else if( make >= 0x47 && numLock) key = keyrow[1]; if (key == 0)//排除非可显示字符 continue; //此时,key已经是可显示字符的ASCII码了,下面根据需要进行处理 moutput[0]= key;// key & 0xFF; disp_str(moutput);//简单显示出来 } freeKeyBuf->idx = 0; }