一步步写操作系统之第四步:创建键盘中断处理模块和初步搭建程序执行系统
键盘中断处理模块:在前一步,已经可以对键盘中断有反应了,但是按下一次键盘按钮后,就不再反应了。这是因为,必须要向键盘数据端口取出从键盘传来的扫描码后,才会继续等待与保存下一个键盘中断产生的扫描码。
t_8 scan_code = in_byte(KB_DATA); //获取扫描码,KB_DATA为键盘数据端口: 0x60
键盘每个按钮按下时和持续按下不松开会产生键盘中断,以及对应按键的扫描码(scan_code),松开时,也会产生键盘中断,此时对应键盘提供的叫做中断码(Break Code),详情见“keyboard.h”的宏定义。
对于同一个键盘按钮,扫描码和中断码有如下关系:
扫描码(scan_code)+ 0x80 = 中断码(Break Code)
此外,一些特殊的键盘按钮,会有E0或E1前缀。
总之,扫描码(中断码)与对应的ASCII码和功能键的映射有自己的一套规则。在编写键盘驱动时,为了简便,都是建立一个数组,通过使用扫描码或是换算成扫描码的中断码作为下标,查找到对应的按键ASCII码或功能键。具体见 “keyboard.h”里的keymap[]数组。对于一些组合键,再进行特殊处理。
关于键盘中断处理,就解释到这,很多的,可以看看下面“keyboard.h”和“keyboard.c”等具体的代码。
程序执行系统:
程序执行系统,或者说“域结构”是我的操作系统特有的一个执行机制,用于代替普通的操作系统里的进程调度机制。简单的说,“域结构”就是一个双向链表,每个节点都包含一个无参无fanh值的函数(执行函数)。通过不断循环调用每个节点的执行函数以及动态的添加或删除执行函数节点形成的一个程序执行系统。
与普通的操作系统里的进程调度机制相比,“域结构”机制是以函数为单位依次轮换执行,而进程调度是以进程(某个独立的程序)为单位根据调度算法轮换执行。
相对来说,“域结构”机制有诸多缺点,最大的一个问题是可靠性与安全性。但是出于个人原因,我还是选择了使用这种调用机制。
键盘中断处理模块,虽然是通过“域结构”调用的,但是基本的流程还是和常用的键盘驱动程序一样。但这只是暂时测试用的,使用“域结构”编写的“域程序”需要遵循特定的规则,在接下来的几步里,会逐步改进“域结构”并修改这个键盘处理模块。
下面是此次修改了的文件和新添加的文件:
code:i8259.c(改)
因为修改不大,仅是修改了一个函数,所以不全部贴出来了。
将:
程序代码:
#pragma align(16) asm void hwint01() //Interrupt routine for irq 1 (keyboard) { hwint_master(1) }改为:(就是将原来的宏hwint_master(1),展开为具体代码,并将调用中断处理函数表的函数改为调用OnKeyEvent()函数)
程序代码:
#pragma align(16) asm void hwint01() //Interrupt routine for irq 1 (keyboard) { pushad // ┓ push ds // ┃ push es // ┣ 保存原寄存器值 push fs // ┃ push gs // ┛ in al, INT_M_CTLMASK // ┓ or al, (1 << 1) // ┣ 屏蔽当前中断 out INT_M_CTLMASK, al // ┛ mov al, EOI // ┓置EOI位,其后8259A才能相应新的中断 out INT_M_CTL, al // ┛ sti //允许响应新的中断 call OnKeyEvent // 调用键盘中断处理程序 cli in al, INT_M_CTLMASK // ┓ and al, ~(1 << 1) // ┣ 恢复接受当前中断 out INT_M_CTLMASK, al // ┛ pop gs // ┓ pop fs // ┃ pop es // ┣ 还原寄存器值 pop ds // ┃ popad // ┛ iretd }
code:kernel.c(改)
程序代码:
//文件:kernel.c //功能:内核程序,目前功能为测试print.c里的几个输出函数 //运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。 //作者:miao //时间:2010-5-24 #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 "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;//初始化根域生命值 AddAction(nullAction); disp_str(" load keyboard action --------------- "); AddAction(keyBoard);//加载键盘服务域 disp_str("ok\n"); disp_str("================ init end ===================\n"); } int kernel_main() { disp_str("================ yu start ===================\n"); 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"
code:yu.h(新)
程序代码:
//文件:yu.h //功能:yu头文件,域结构需要用到的公共函数的声明等 //作者:miao //时间:2010-5-24 #define NULL 0 typedef void (*action_fun)(); //动作结构 struct action_s { char *name; //动作名称 action_fun run; //动作调用的函数 struct action_s *last; //上一动作 struct action_s *next; //下一动作 }; //动作链表 struct actionList_s { unsigned int count; //动作计数器 struct action_s *seek; //当前动作 }actionList = {0,NULL}; //根域生命值(为零,退出域动作链表循环) int life = 0; //添加一个动作到动作链表表里 void AddAction(struct action_s *newAction); //从动作链表里删除一个动作 void DelAction(struct action_s *delAction); void Run(); //执行当前动作 void NullActionFun();//空动作,限制链表执行速度或将来用于管理动作链表 struct action_s nullAction = {"NullFun",&NullActionFun,NULL,NULL};
code:yu.c(新)
程序代码:
//文件:yu.c //功能:域结构,管理一个动作双向链表,循环执行链表上的动作函数 //作者:miao //时间:2010-5-24 //添加一个动作到动作链表里 void AddAction(struct action_s *newAction) { if((*newAction).next != NULL) { 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) { if((*delAction).next == NULL) { 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--; } void Run() { //执行当前动作 if(actionList.seek != NULL) { (*actionList.seek).run(); } //OnRun();//执行on事件 //指向下一个动作 if(actionList.seek != NULL) actionList.seek = (*actionList.seek).next; } //空动作,限制链表执行速度或将来用于管理动作链表 void NullActionFun() { for(int i=0;i<100;i++) for(int j=0;j<1999;j++); asm { inc word gs:[((80 * 0+ 0) * 0)] } }
code:keyboard.h(新)
程序代码:
//文件:keyboard.h //功能:keyboard头文件,内核需要用到的公共函数的声明等 //作者:miao //时间:2010-5-24 //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 FLAG_BREAK 0x0080 //通过scan_code & FLAG_BREAK 来判断是否是Break Code #define FLAG_EXT 0x0100 //标准功能键 #define FLAG_SHIFT_L 0x0200 //Shift左键 #define FLAG_SHIFT_R 0x0400 //Shift右键 #define FLAG_CTRL_L 0x0800 //Control左键 #define FLAG_CTRL_R 0x1000 //Control右键 #define FLAG_ALT_L 0x2000 //Alternate左键 #define FLAG_ALT_R 0x4000 //Alternate右键 #define FLAG_PAD 0x8000 //数字区的键 //键扫描码:具体的值请参考keymap最右边的列或者下表 #define MASK_RAW 0x01FF //特殊功能键 #define ESC (0x01 + FLAG_EXT) // Esc #define TAB (0x02 + FLAG_EXT) // Tab #define ENTER (0x03 + FLAG_EXT) // Enter #define BACKSPACE (0x04 + FLAG_EXT) // BackSpace #define GUI_L (0x05 + FLAG_EXT) // L GUI #define GUI_R (0x06 + FLAG_EXT) // R GUI #define APPS (0x07 + FLAG_EXT) // APPS //Shift, Ctrl, Alt #define SHIFT_L (0x08 + FLAG_EXT) // L Shift #define SHIFT_R (0x09 + FLAG_EXT) // R Shift #define CTRL_L (0x0A + FLAG_EXT) // L Ctrl #define CTRL_R (0x0B + FLAG_EXT) // R Ctrl #define ALT_L (0x0C + FLAG_EXT) // L Alt #define ALT_R (0x0D + FLAG_EXT) // R Alt //锁定键 #define CAPS_LOCK (0x0E + FLAG_EXT) // 大写锁定键 #define NUM_LOCK (0x0F + FLAG_EXT) // 数字锁定键 #define SCROLL_LOCK (0x10 + FLAG_EXT) // 屏幕滚动锁定键 //功能键 #define F1 (0x11 + FLAG_EXT) // F1 #define F2 (0x12 + FLAG_EXT) // F2 #define F3 (0x13 + FLAG_EXT) // F3 #define F4 (0x14 + FLAG_EXT) // F4 #define F5 (0x15 + FLAG_EXT) // F5 #define F6 (0x16 + FLAG_EXT) // F6 #define F7 (0x17 + FLAG_EXT) // F7 #define F8 (0x18 + FLAG_EXT) // F8 #define F9 (0x19 + FLAG_EXT) // F9 #define F10 (0x1A + FLAG_EXT) // F10 #define F11 (0x1B + FLAG_EXT) // F11 #define F12 (0x1C + FLAG_EXT) // F12 //控制区 #define PRINTSCREEN (0x1D + FLAG_EXT) // Print Screen #define PAUSEBREAK (0x1E + FLAG_EXT) // Pause/Break #define INSERT (0x1F + FLAG_EXT) // Insert #define DELETE (0x20 + FLAG_EXT) // Delete #define HOME (0x21 + FLAG_EXT) // Home #define END (0x22 + FLAG_EXT) // End #define PAGEUP (0x23 + FLAG_EXT) // Page Up #define PAGEDOWN (0x24 + FLAG_EXT) // Page Down #define UP (0x25 + FLAG_EXT) // Up #define DOWN (0x26 + FLAG_EXT) // Down #define LEFT (0x27 + FLAG_EXT) // Left #define RIGHT (0x28 + FLAG_EXT) // Right //电源管理键 #define POWER (0x29 + FLAG_EXT) // Power #define SLEEP (0x2A + FLAG_EXT) // Sleep #define WAKE (0x2B + FLAG_EXT) // Wake Up //数字区 #define PAD_SLASH (0x2C + FLAG_EXT) // / #define PAD_STAR (0x2D + FLAG_EXT) // * #define PAD_MINUS (0x2E + FLAG_EXT) // - #define PAD_PLUS (0x2F + FLAG_EXT) // + #define PAD_ENTER (0x30 + FLAG_EXT) // Enter #define PAD_DOT (0x31 + FLAG_EXT) // . #define PAD_0 (0x32 + FLAG_EXT) // 0 #define PAD_1 (0x33 + FLAG_EXT) // 1 #define PAD_2 (0x34 + FLAG_EXT) // 2 #define PAD_3 (0x35 + FLAG_EXT) // 3 #define PAD_4 (0x36 + FLAG_EXT) // 4 #define PAD_5 (0x37 + FLAG_EXT) // 5 #define PAD_6 (0x38 + FLAG_EXT) // 6 #define PAD_7 (0x39 + FLAG_EXT) // 7 #define PAD_8 (0x3A + FLAG_EXT) // 8 #define PAD_9 (0x3B + FLAG_EXT) // 9 #define PAD_UP PAD_8 // Up #define PAD_DOWN PAD_2 // Down #define PAD_LEFT PAD_4 // Left #define PAD_RIGHT PAD_6 // Right #define PAD_HOME PAD_7 // Home #define PAD_END PAD_1 // End #define PAD_PAGEUP PAD_9 // Page Up #define PAD_PAGEDOWN PAD_3 // Page Down #define PAD_INS PAD_0 // Ins #define PAD_MID PAD_5 // Middle key #define PAD_DEL PAD_DOT // Del #define MAP_COLS 3 //keymap 的列数 #define NR_SCAN_CODES 0x80 //扫描码的数目(keymap的行数) t_32 keymap[NR_SCAN_CODES * MAP_COLS] = { //shift未按下 shift按下 有0xE0前缀的扫描码 //!Shift Shift E0 XX 扫描码 0, 0, 0, //0x00 - none ESC, ESC, 0, //0x01 - ESC '1', '!', 0, //0x02 - '1' '2', '@', 0, //0x03 - '2' '3', '#', 0, //0x04 - '3' '4', '$', 0, //0x05 - '4' '5', '%', 0, //0x06 - '5' '6', '^', 0, //0x07 - '6' '7', '&', 0, //0x08 - '7' '8', '*', 0, //0x09 - '8' '9', '(', 0, //0x0A - '9' '0', ')', 0, //0x0B - '0' '-', '_', 0, //0x0C - '-' '=', '+', 0, //0x0D - '=' BACKSPACE, BACKSPACE, 0, //0x0E - BS TAB, TAB, 0, //0x0F - TAB 'q', 'Q', 0, //0x10 - 'q' 'w', 'W', 0, //0x11 - 'w' 'e', 'E', 0, //0x12 - 'e' 'r', 'R', 0, //0x13 - 'r' 't', 'T', 0, //0x14 - 't' 'y', 'Y', 0, //0x15 - 'y' 'u', 'U', 0, //0x16 - 'u' 'i', 'I', 0, //0x17 - 'i' 'o', 'O', 0, //0x18 - 'o' 'p', 'P', 0, //0x19 - 'p' '[', '{', 0, //0x1A - '[' ']', '}', 0, //0x1B - ']' ENTER, ENTER, PAD_ENTER, //0x1C - CR/LF CTRL_L, CTRL_L, CTRL_R, //0x1D - l. Ctrl 'a', 'A', 0, //0x1E - 'a' 's', 'S', 0, //0x1F - 's' 'd', 'D', 0, //0x20 - 'd' 'f', 'F', 0, //0x21 - 'f' 'g', 'G', 0, //0x22 - 'g' 'h', 'H', 0, //0x23 - 'h' 'j', 'J', 0, //0x24 - 'j' 'k', 'K', 0, //0x25 - 'k' 'l', 'L', 0, //0x26 - 'l' ';', ':', 0, //0x27 - ';' '\'', '"', 0, //0x28 - '\'' '`', '~', 0, //0x29 - '`' SHIFT_L, SHIFT_L, 0, //0x2A - l. SHIFT '\\', '|', 0, //0x2B - '\' 'z', 'Z', 0, //0x2C - 'z' 'x', 'X', 0, //0x2D - 'x' 'c', 'C', 0, //0x2E - 'c' 'v', 'V', 0, //0x2F - 'v' 'b', 'B', 0, //0x30 - 'b' 'n', 'N', 0, //0x31 - 'n' 'm', 'M', 0, //0x32 - 'm' ',', '<', 0, //0x33 - ',' '.', '>', 0, //0x34 - '.' '/', '?', PAD_SLASH, //0x35 - '/' SHIFT_R, SHIFT_R, 0, //0x36 - r. SHIFT '*', '*', 0, //0x37 - '*' ALT_L, ALT_L, ALT_R, //0x38 - ALT ' ', ' ', 0, //0x39 - ' ' CAPS_LOCK, CAPS_LOCK, 0, //0x3A - CapsLock F1, F1, 0, //0x3B - F1 F2, F2, 0, //0x3C - F2 F3, F3, 0, //0x3D - F3 F4, F4, 0, //0x3E - F4 F5, F5, 0, //0x3F - F5 F6, F6, 0, //0x40 - F6 F7, F7, 0, //0x41 - F7 F8, F8, 0, //0x42 - F8 F9, F9, 0, //0x43 - F9 F10, F10, 0, //0x44 - F10 NUM_LOCK, NUM_LOCK, 0, //0x45 - NumLock SCROLL_LOCK, SCROLL_LOCK, 0, //0x46 - ScrLock PAD_HOME, '7', HOME, //0x47 - Home PAD_UP, '8', UP, //0x48 - CurUp PAD_PAGEUP, '9', PAGEUP, //0x49 - PgUp PAD_MINUS, '-', 0, //0x4A - '-' PAD_LEFT, '4', LEFT, //0x4B - Left PAD_MID, '5', 0, //0x4C - MID PAD_RIGHT, '6', RIGHT, //0x4D - Right PAD_PLUS, '+', 0, //0x4E - '+' PAD_END, '1', END, //0x4F - End PAD_DOWN, '2', DOWN, //0x50 - Down PAD_PAGEDOWN, '3', PAGEDOWN, //0x51 - PgDown PAD_INS, '0', INSERT, //0x52 - Insert PAD_DOT, '.', DELETE, //0x53 - Delete 0, 0, 0, //0x54 - Enter 0, 0, 0, //0x55 - ??? 0, 0, 0, //0x56 - ??? F11, F11, 0, //0x57 - F11 F12, F12, 0, //0x58 - F12 0, 0, 0, //0x59 - ??? 0, 0, 0, //0x5A - ??? 0, 0, GUI_L, //0x5B - ??? 0, 0, GUI_R, //0x5C - ??? 0, 0, APPS, //0x5D - ??? 0, 0, 0, //0x5E - ??? 0, 0, 0, //0x5F - ??? 0, 0, 0, //0x60 - ??? 0, 0, 0, //0x61 - ??? 0, 0, 0, //0x62 - ??? 0, 0, 0, //0x63 - ??? 0, 0, 0, //0x64 - ??? 0, 0, 0, //0x65 - ??? 0, 0, 0, //0x66 - ??? 0, 0, 0, //0x67 - ??? 0, 0, 0, //0x68 - ??? 0, 0, 0, //0x69 - ??? 0, 0, 0, //0x6A - ??? 0, 0, 0, //0x6B - ??? 0, 0, 0, //0x6C - ??? 0, 0, 0, //0x6D - ??? 0, 0, 0, //0x6E - ??? 0, 0, 0, //0x6F - ??? 0, 0, 0, //0x70 - ??? 0, 0, 0, //0x71 - ??? 0, 0, 0, //0x72 - ??? 0, 0, 0, //0x73 - ??? 0, 0, 0, //0x74 - ??? 0, 0, 0, //0x75 - ??? 0, 0, 0, //0x76 - ??? 0, 0, 0, //0x77 - ??? 0, 0, 0, //0x78 - ??? 0, 0, 0, //0x78 - ??? 0, 0, 0, //0x7A - ??? 0, 0, 0, //0x7B - ??? 0, 0, 0, //0x7C - ??? 0, 0, 0, //0x7D - ??? 0, 0, 0, //0x7E - ??? 0, 0, 0 //0x7F - ??? }; #define KB_IN_BYTES 32 //键盘输入缓冲区大小 struct s_kb { char *p_head; //指向缓冲区中下一个空闲位置 char *p_tail; //指向键盘任务应处理的字节 int count; //缓冲区中共有多少字节 char buf[KB_IN_BYTES]; //缓冲区 }; struct s_kb *keyBufPoint; int *keyBoardLifePOint; void OnKeyEvent(); //键盘中断处理函数 //键盘服务系统相关 int kb_life = 0; struct s_kb kb_in; t_bool code_with_E0 = FALSE; t_bool shift_l; // l shift 状态 t_bool shift_r; // r shift 状态 t_bool alt_l; // l alt 状态 t_bool alt_r; // r left 状态 t_bool ctrl_l; // l ctrl 状态 t_bool ctrl_r; // l ctrl 状态 t_bool caps_lock; // Caps Lock t_bool num_lock; // Num Lock t_bool scroll_lock; // Scroll Lock int column = 0; // keyrow[column] 将是 keymap 中某一个值 void init_keyboard();//初始化键盘 void KeyBoardFun();//键盘动作函数 struct action_s keyBoard = {"keyBoard",&KeyBoardFun,NULL,NULL};
code:keyboard.c(新)
程序代码:
//文件:keyboard.c //功能:初始化键盘、以及设置中断相关的函数 //作者:miao //时间:2010-5-24 //键盘中断处理函数 void OnKeyEvent() { //disp_str(" OnKeyEvent "); t_8 scan_code = in_byte(KB_DATA); //获取扫描码 //disp_int(scan_code); //将扫描法放入缓冲区 if(keyBufPoint->count < KB_IN_BYTES) //若缓冲区未满,将信息记录 { *(keyBufPoint->p_head++) = scan_code; //记录扫描码 if(keyBufPoint->p_head == keyBufPoint->buf + KB_IN_BYTES) keyBufPoint->p_head = keyBufPoint->buf; keyBufPoint->count++; } //启动键盘域 if(*keyBoardLifePOint >= 0) (*keyBoardLifePOint)++; } //键盘中断初始化函数 void init_keyboard() { //注册键盘中断处理域:指定键盘域的life指针 keyBoardLifePOint = &kb_life; kb_life = 0;//键盘域的生命值 keyBufPoint = &kb_in; //初始化键盘缓冲区 kb_in.count = 0; kb_in.p_head = kb_in.p_tail = kb_in.buf; //初始化键盘标记 caps_lock = 0; num_lock = 1; scroll_lock = 0; enable_irq(KEYBOARD_IRQ); //开键盘中断 } void keyboard_read();//测试函数,将扫描码中的可显示字符显示到屏幕上 void KeyBoardFun() { if(kb_life > 0) { keyboard_read();//显示所按键 kb_life--; //disp_int(kb_life); } } /////////////////////以下为测试用////////////////////////////// char output[] = "&"; void in_process(t_32 key) { if (!(key & FLAG_EXT)) { output[0] = key & 0xFF; disp_str(output); } } //从键盘缓冲区中读取下一个字节 t_8 get_byte_from_kb_buf() { t_8 scan_code; //若键盘缓冲区为空,等待 while(kb_in.count <= 0) disp_str("*"); asm{cli} scan_code = *(kb_in.p_tail++); if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) kb_in.p_tail = kb_in.buf; kb_in.count--; asm{sti} return scan_code; } //从键盘数据缓冲区读取数据 void keyboard_read() { t_8 scan_code; t_bool make; //TRUE:make FALSE:break t_32 key = 0; //用一个整型来表示一个键。 //比如,如果 Home 被按下,则 key 值将为定义在 keyboard.h 中的 'HOME'。 t_32 *keyrow; //指向 keymap[] 的某一行 if(kb_in.count <= 0)//若键盘缓冲区为空,不处理 { disp_str("+"); return; } code_with_E0 = FALSE; scan_code = get_byte_from_kb_buf(); if(scan_code== -1) return; //下面开始解析扫描码 if (scan_code == 0xE1) { int i; t_8 pausebreak_scan_code[] = {0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5}; t_bool is_pausebreak = TRUE; for(i=1;i<6;i++) { if (get_byte_from_kb_buf() != pausebreak_scan_code[i]) { is_pausebreak = FALSE; break; } } if (is_pausebreak) key = PAUSEBREAK; } else if (scan_code == 0xE0) { scan_code = get_byte_from_kb_buf(); //PrintScreen 被按下 if(scan_code == 0x2A && get_byte_from_kb_buf() == 0xE0 && get_byte_from_kb_buf() == 0x37 ) { key = PRINTSCREEN; make = TRUE; } //PrintScreen 被释放 if(scan_code == 0xB7 && get_byte_from_kb_buf() == 0xE0 && get_byte_from_kb_buf() == 0xAA ) { key = PRINTSCREEN; make = FALSE; } //不是 PrintScreen。此时 scan_code 为 0xE0 紧跟的那个值。 if (key == 0) code_with_E0 = TRUE; } if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) { //首先判断Make Code 还是 Break Code make = (scan_code & FLAG_BREAK ? FALSE : TRUE); //先定位到 keymap 中的行 keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS]; column = 0; if (shift_l || shift_r) column = 1; if (code_with_E0) column = 2; key = keyrow[column]; switch(key) { case SHIFT_L: shift_l = make; break; case SHIFT_R: shift_r = make; break; case CTRL_L: ctrl_l = make; break; case CTRL_R: ctrl_r = make; break; case ALT_L: alt_l = make; break; case ALT_R: alt_l = make; break; default: break; } } //忽略 Break Code if(make) { key |= shift_l ? FLAG_SHIFT_L : 0; key |= shift_r ? FLAG_SHIFT_R : 0; key |= ctrl_l ? FLAG_CTRL_L : 0; key |= ctrl_r ? FLAG_CTRL_R : 0; key |= alt_l ? FLAG_ALT_L : 0; key |= alt_r ? FLAG_ALT_R : 0; in_process(key); } }
[ 本帖最后由 miaowangjian 于 2010-5-31 16:14 编辑 ]