• 自制操作系统日志——第十七天


    自制操作系统日志——第十七天

    今天,我们首先继续稍微完善一下多任务的部分。然后,我们开始制作每一个操作系统都必须有的命令行窗口吧!!!从今天开始,我们将一步一步的完成我们的命令行窗口,并能够输入一些命令进行调用吧!

    嘿嘿嘿想想就有点激动了!!让我们现在就开始撸起袖子加油干吧。



    一、设置闲置任务

    在昨天的多任务机制中,我们还有一些小地方还需要进一步的完善一下。比如说,假设我们的任务b系列已经完成了工作,也就是说此时任务b系列的都没有启动,那么由于我们设置了任务a在没有对应的中断信息产生时就会休眠,那此时所有级别中的任务都没有了,那这样子可能就会因为找不到其他任务而导致运行出现异常的!!

    那么该怎么来解决这个问题呢??? 仔细一想,我们是否还记得之前有一个技巧叫“哨兵” ,对的我们可以利用哨兵这个技巧来设置一个闲置的任务,以此防止运行出现异常:
    mtask.c

    //多任务的哨兵,idle代表闲置。以防止当鼠标的那个任务进入休眠,下面又没有其他任务时多任务系统破溃
    void task_idle(void)
    {
        for(;;){
            io_hlt();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然后进一步的修改一下task_init函数:

    //返回一个内存地址,将当前运行的调用该函数的程序作为一个任务
    struct TASK *task_init(struct MEMMAN *memman)
    {
        int i;
        struct TASK *task, *idle;
        struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
        taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));
        for(i = 0; i < MAX_TASKS; i++)
        {
            taskctl->tasks0[i].flags = 0;
            taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;
            set_segmdesc(gdt + TASK_GDT0 +i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);
        }
        for (i = 0; i < MAX_TASKLEVELS; i++) {
    		taskctl->level[i].running = 0;
    		taskctl->level[i].now = 0;
    	}
        task = task_alloc();//接收到akkoc返回的第一个任务
        task->flags = 2;//活动中的标志
        task->priority = 2;//0.02s
        task->level = 0; //先将当前调用程序的任务暂时设置为0,即最高
        task_add(task);
        task_switchsub();//level 设置
        load_tr(task->sel);
        task_timer = timer_alloc();
        timer_settime(task_timer, task->priority);
    
        idle = task_alloc();
        idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
        idle->tss.eip = (int) &task_idle;
        idle->tss.es  = 1 * 8;
        idle->tss.cs  = 2 * 8;
        idle->tss.ss  = 1 * 8;
        idle->tss.ds  = 1 * 8;
        idle->tss.fs  = 1 * 8;
        idle->tss.gs  = 1 * 8;
        task_run(idle, MAX_TASKLEVELS - 1, 1);//将哨兵置于最底层的最后一个任务
    
        return task;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    最后,我们将之前的task_b这个部分的任务启动关闭:

    	for (i = 0; i < 3; i++) {
    	//task_run(task_b[i], 2, i + 1);
    
    • 1
    • 2

    在这里插入图片描述
    发现确实可行,任务b的三个子程序都没有进行计数了!

    二、创建命令行

    先制作窗口

    这里,我们一步一步的来,首先呢先把大致的窗口做出来:
    主函数:

    	/* sht_cons */
    	sht_cons = sheet_alloc(shtctl);
    	buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
    	sheet_setbuf(sht_cons, buf_cons, 256, 165, -1); /* 透明色なし */
    	make_window8(buf_cons, 256, 165, "console-yuan", 0);
    	make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000);
    	task_cons = task_alloc();
    	task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;
    	task_cons->tss.eip = (int) &console_task;
    	task_cons->tss.es = 1 * 8;
    	task_cons->tss.cs = 2 * 8;
    	task_cons->tss.ss = 1 * 8;
    	task_cons->tss.ds = 1 * 8;
    	task_cons->tss.fs = 1 * 8;
    	task_cons->tss.gs = 1 * 8;
    	*((int *) (task_cons->tss.esp + 4)) = (int) sht_cons;
    	task_run(task_cons, 2, 2); /* level=2, priority=2 */
    
    
    	sheet_slide(sht_back,  0,  0);
    	sheet_slide(sht_cons, 32,  4);
    	sheet_slide(sht_win,  64, 56);
    	sheet_slide(sht_mouse, mx, my);
    	sheet_updown(sht_back,  0);
    	sheet_updown(sht_cons,  1);
    	sheet_updown(sht_win,   2);
    	sheet_updown(sht_mouse, 3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    修改窗口的函数:
    bootpack.c:

    void console_task(struct SHEET *sheet)
    {
    	struct FIFO32 fifo;
    	struct TIMER *timer;
    	struct TASK * task = task_now();
    
    	int i, fifobuf[32], cursor_x = 8, cursor_c = COL8_000000;
    	fifo32_init(&fifo, 128, fifobuf, task);
    
    	timer = timer_alloc();
    	timer_init(timer, &fifo, 1);
    	timer_settime(timer, 50);
    
    	for(;;){
    		io_cli();
    		if(fifo32_status(&fifo) == 0){
    			task_sleep(task);
    			io_sti();
    		}else{
    			i = fifo32_get(&fifo);
    			io_sti();
    			if(i <= 1){//光标用的定时器
    			    if(i != 0){
    					timer_init(timer, &fifo, 0);//下次置于0
    					cursor_c = COL8_FFFFFF;
    				}else{
    					timer_init(timer, &fifo, 1);//下次置于1
    					cursor_c = COL8_000000;
    				}
    				timer_settime(timer, 50);
    				boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
    				sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44);
    			}
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    这里,其实没啥难度的,这些窗口的制作啊啥的,直接利用前面的就可以了:

    在这里插入图片描述

    能够象征性的切换窗口

    这里我们的目的主要就,当我们按下tab键后这两个窗口能进行切换,即一开始是task_a的标题栏是显示的,而console是灰色的。 当我们按下tab后,console是显示的,而task这个变灰了:
    具体修改:先将之前的窗口拆分成标题栏和窗口其余部分:

    //窗口的剩余部分
    void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act)
    {
    	boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
    	boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
    	boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
    	boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
    	boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
    	boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
    	boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
    	boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
    	boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
    	make_wtitle8(buf, xsize, title, act);
    	return;
    }
    //窗口的标题栏
    void make_wtitle8(unsigned char *buf, int xsize, char *title, char act)
    {
    	static char closebtn[14][16] = {
    		"OOOOOOOOOOOOOOO@",
    		"OQQQQQQQQQQQQQ$@",
    		"OQQQQQQQQQQQQQ$@",
    		"OQQQ@@QQQQ@@QQ$@",
    		"OQQQQ@@QQ@@QQQ$@",
    		"OQQQQQ@@@@QQQQ$@",
    		"OQQQQQQ@@QQQQQ$@",
    		"OQQQQQ@@@@QQQQ$@",
    		"OQQQQ@@QQ@@QQQ$@",
    		"OQQQ@@QQQQ@@QQ$@",
    		"OQQQQQQQQQQQQQ$@",
    		"OQQQQQQQQQQQQQ$@",
    		"O$$$$$$$$$$$$$$@",
    		"@@@@@@@@@@@@@@@@"
    	};
    	int x, y;
    	char c, tc, tbc;
    	if (act != 0) {
    		tc = COL8_FFFFFF;
    		tbc = COL8_000084;
    	} else {
    		tc = COL8_C6C6C6;
    		tbc = COL8_848484;
    	}
    	boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20);
    	putfonts8_asc(buf, xsize, 24, 4, tc, title);
    	for (y = 0; y < 14; y++) {
    		for (x = 0; x < 16; x++) {
    			c = closebtn[y][x];
    			if (c == '@') {
    				c = COL8_000000;
    			} else if (c == '$') {
    				c = COL8_848484;
    			} else if (c == 'Q') {
    				c = COL8_C6C6C6;
    			} else {
    				c = COL8_FFFFFF;
    			}
    			buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
    		}
    	}
    	return;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    然后,修改主函数里的关于键盘输入部分,具体增加如下:

    					if(i == 256 + 0x0f){//tab键
    					    if(key_to == 0){//通过0, 1 来决定将哪一个标题栏显示,哪一个变成灰色
    							key_to = 1;
    							make_wtitle8(buf_win,  sht_win->bxsize,  "task_a", 0);
    							make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
    						}else{
    							key_to = 0;
    							make_wtitle8(buf_win,  sht_win->bxsize,  "task_a", 1);
    							make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
    						}
    						sheet_refresh(sht_win,	0,	0, sht_win->bxsize,  21);
    						sheet_refresh(sht_cons,	0,	0, sht_cons->bxsize, 21);
    					}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后,运行,按下tab键后就可以看见确实切换了:
    在这里插入图片描述

    对命令行输入字符串

    要想输入字符串呢,依据我们task_a的处理,就是把键盘产生的中断数据,放入到FIFO缓冲区。那么这里,我们也利用同样的思路进行输送字符吧!

    但是有一点,就是我在task_cons这个任务里所建立的fifo缓冲区,是不与主程序的fifo缓冲区所共享的,那么我们任务A里想要把键盘数据发送过去,就必须找到任务B的fifo的地址。 如果直接利用任务A创建时告诉任务B的fifo地址的这种方法的话,我感觉略显麻烦! 那么,我们可以直接在任务结构体TASK中增加一个声明指向fifo缓冲区即可。 具体的修改如下:
    bootpack.h:

    struct TASK
    {
    	int sel, flags; //sel用于存放GDT编号
    	int level, priority; //设置优先级
    	struct FIFO32 fifo;
    	struct TSS32 tss;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    而后,修改一下console这个任务:

    void console_task(struct SHEET *sheet)
    {
    	struct TIMER *timer;
    	struct TASK * task = task_now();
    	int i, fifobuf[32], cursor_x = 16, cursor_c = COL8_000000;
    	char s[2];
    
    	fifo32_init(&task->fifo, 128, fifobuf, task);
    	timer = timer_alloc();
    	timer_init(timer, &task->fifo, 1);
    	timer_settime(timer, 50);
    
        //显示提示符
    	putfonts8_asc_sht(sheet, 8, 28, COL8_FFFFFF, COL8_000000, ">", 1);
    
    	for(;;){
    		io_cli();
    		if(fifo32_status(&task->fifo) == 0){
    			task_sleep(task);
    			io_sti();
    		}else{
    			i = fifo32_get(&task->fifo);
    			io_sti();
    			if(i <= 1){//光标用的定时器
    			    if(i != 0){
    					timer_init(timer, &task->fifo, 0);//下次置于0
    					cursor_c = COL8_FFFFFF;
    				}else{
    					timer_init(timer, &task->fifo, 1);//下次置于1
    					cursor_c = COL8_000000;
    				}
    				timer_settime(timer, 50);
    			}
    			if(256 <= i && i<= 511){
    				//键盘数据通过任务a
    				if(i == 8+ 256){
    					//退格键
    					if(cursor_x > 16){
    						//用空白擦除光标后,光标前移一位
    						putfonts8_asc_sht(sheet, cursor_x, 28, COL8_FFFFFF, COL8_000000, " ", 1);
    						cursor_x -= 8;
    					}
    				}else{
    					//一般文字
    					if(cursor_x < 240){
    						//显示一个字符后光标后移
    						s[0] = i - 256;
    						s[1] = 0;
    						putfonts8_asc_sht(sheet, cursor_x, 28, COL8_FFFFFF, COL8_000000, s, 1);
    						cursor_x += 8;
    					}
    				}
    			}
    			boxfill8(sheet->buf, sheet->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
    			sheet_refresh(sheet, cursor_x, 28, cursor_x + 8, 44);
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    然后,我们还需对主函数的传递进行控制一下,以确定是传给哪一个任务的:

    for(;;)   
    	{
    		io_cli(); //IF=0
    		if (fifo32_status(&fifo) == 0)
    		{
    			task_sleep(task_a);
    			io_sti();
    		}else 
    		{ 
    			i = fifo32_get(&fifo);
    			io_sti();
    			if (256 <= i && i <= 511) { /*键盘数据 */
    				sprintf(s, "%02X", i - 256);
    				putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
    				if( i < 0x54 + 256 && keytable[i - 256] != 0)//一般字符
    				{
    					if(key_to == 0){
    						//发送给任务a
    						if( cursor_x < 128){
    							//显示一个字符光标就向后移动一次
    							s[0] = keytable[i-256];
    							s[1] = 0;
    							putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_C6C6C6, s, 1);
    							cursor_x +=8;
    						}
    					}else{
    						//发送给命令行
    						fifo32_put(&task_cons->fifo, keytable[i - 256] + 256);
    					}
    				}
    					if(i == 256 + 0x0e ) //退格键
    					{//用空格把光标消去后移动一次
    					    if(key_to == 0){
    							if(cursor_x > 8){
    								putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
    								cursor_x -=8;
    							}
    						}else{
    							fifo32_put(&task_cons->fifo, 8 +256);//z这里定义在console中退格键的编码为8
    						}
    					}
    					if(i == 256 + 0x0f){//tab键
    					    if(key_to == 0){//通过0, 1 来决定将哪一个标题栏显示,哪一个变成灰色
    							key_to = 1;
    							make_wtitle8(buf_win,  sht_win->bxsize,  "task_a", 0);
    							make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
    						}else{
    							key_to = 0;
    							make_wtitle8(buf_win,  sht_win->bxsize,  "task_a", 1);
    							make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
    						}
    						sheet_refresh(sht_win,	0,	0, sht_win->bxsize,  21);
    						sheet_refresh(sht_cons,	0,	0, sht_cons->bxsize, 21);
    					}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    然后,make run 一下即可运行:
    在这里插入图片描述

    符号的输入

    在此之前,我们即使想要输入键盘的!是无法做到的,这是因为我们想要产生这一个按键,是需要我们利用起shift的。因此,我们在这里需要建立起支持shift产生特殊字符的功能!! (对了,插一句题外话,目前我们使用的编码字符是小键盘喔!)

    我们设置一个变量key_shift , 当左shift按下时置为1, 当右shift按下时 置为2,左右同时按下,则置为3.。。

    然后设置两个字符表,一个是没按下shift的,一个按下后的:

    	static char keytable0[0x80] = {
    		0,   0,   '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0,   0,
    		'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0,   0,   'A', 'S',
    		'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0,   0,   ']', 'Z', 'X', 'C', 'V',
    		'B', 'N', 'M', ',', '.', '/', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
    		0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
    		'2', '3', '0', '.', 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    		0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    		0,   0,   0,   0x5c, 0,  0,   0,   0,   0,   0,   0,   0,   0,   0x5c, 0,  0
    	};
    	static char keytable1[0x80] = {
    		0,   0,   '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0,   0,
    		'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0,   0,   'A', 'S',
    		'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0,   0,   '}', 'Z', 'X', 'C', 'V',
    		'B', 'N', 'M', '<', '>', '?', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
    		0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
    		'2', '3', '0', '.', 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    		0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    		0,   0,   0,   '_', 0,   0,   0,   0,   0,   0,   0,   0,   0,   '|', 0,   0
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    然后,我们更改主函数中的for循环:
    其代码逻辑是: 先将按键编码转化为字符编码,将转化结果存于s[0]中,若遇到无法转化的就置为0 。(在此过程中就会判断是否右按下左shift)

    if (256 <= i && i <= 511) { /*键盘数据 */
    				sprintf(s, "%02X", i - 256);
    				putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
    				if(i < 0x80 + 256){
    					//将按键编码转化为字符编码
    					if(key_shift == 0){
    						s[0] = keytable0[i - 256];
    					}else{
    						s[0] = keytable1[i -256];
    					}
    				}else{
    					s[0] = 0;
    				}
    				if( s[0] != 0)//一般字符
    				{
    					if(key_to == 0){
    						//发送给任务a
    						if( cursor_x < 128){
    							//显示一个字符光标就向后移动一次
    							s[1] = 0;
    							putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_C6C6C6, s, 1);
    							cursor_x += 8;
    						}
    					}else{
    						//发送给命令行
    						fifo32_put(&task_cons->fifo, s[0] + 256);
    					}
    				}
    			退格键,tab的代码不变!
    								if(i == 256 + 0x2a){//左shift on
    						key_shift |= 1;
    					}
    					if(i == 256 + 0x36){//右shift on
    						key_shift |= 2;
    					}
    					if(i == 256 + 0xaa){//左shift off
    						key_shift &= ~1;
    					}
    					if(i == 256 + 0xb6){//右shift off
    						key_shift &= ~2;
    					}
    					//光标在显示
    					光标代码!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    然后,就万事大吉了!!来运行一下吧,嘿嘿嘿:
    在这里插入图片描述

    显示大小写字母

    要想区分开大小写的字母,需要我们同时对shift以及CapsLock同时进行判断即可:

    • CapsLock 为 ON 与 shift 为ON ⇒ 小写字母
    • CapsLock 为 OFF 与 shift 为 OFF ⇒ 小写字母
      其余组合均为大写字母,也就是说需要这两个按键同时为ON 或者 同时为OFF 时就可以实现小写的状态!!!

    而我们的CapsLock 需要我们从之前在asmhead.nas中,从bios保存下来的键盘状态的数据里取得,也就是binfo->leds 。 其中:

    • leds的第四位表示 ScrollLock 的状态;
    • leds的第五位表示 NumLock 的状态;
    • leds的第六位表示 CapsLock的状态;
      因此,在我们获取到对应的leds值时,我们经需获取4~6位的数据即可!!!

    还有一件事,即我们设置CapsLock启用后,键盘上的指示灯一般是会亮的!因此,这里还需要我们对键盘的控制电路发送对应的信号,才能实现:

    • 读取寄存器的值,等待bit1的值变为0;
    • 向端口发送要写入的1字节数据;
    • 等待接盘反馈信息,成功返回0xfa , 失败返回0xfe;
    • 控制led灯的状态,就重复上述操作两边,并向键盘发送EDxx 的数据。其中xx的bit0表示ScrollLock , bit1 代表NumLock, bit2 代表CapsLock。

    具体的修改代码如下:
    主函数:

    struct FIFO32 fifo, keycmd;
    	struct SHTCTL *shtctl;//用于管理的
    	int fifobuf[128], keycmd_buf[32];int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1;//为了避免和键盘当前状态冲突,需要一开始先进行设置
    	fifo32_put(&keycmd, KEYCMD_LED);
    	fifo32_put(&keycmd, key_leds);
    	for(;;)   
    	{
    		if(fifo32_status(&keycmd) > 0 && keycmd_wait < 0){
    			//如果存在向键盘控制器发送数据,则进行发送
    			keycmd_wait = fifo32_get(&keycmd);
    			wait_KBC_sendready();
    			io_out8(PORT_KEYDAT, keycmd_wait);
    		}
    		io_cli(); //IF=0
    		if (fifo32_status(&fifo) == 0)
    		{
    			task_sleep(task_a);
    			io_sti();
    		}else 
    		{ 
    			i = fifo32_get(&fifo);
    			io_sti();
    			if (256 <= i && i <= 511) { /*键盘数据 */
    				sprintf(s, "%02X", i - 256);
    				putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
    				if(i < 0x80 + 256){
    					//将按键编码转化为字符编码
    					if(key_shift == 0){
    						s[0] = keytable0[i - 256];
    					}else{
    						s[0] = keytable1[i -256];
    					}
    				}else{
    					s[0] = 0;
    				}
    				if('A' <= s[0] && s[0] <= 'Z'){//当输入的为英文字符时
    					if(((key_leds & 4) == 0 && key_shift == 0) || 
    					     ((key_leds & 4) != 0 && key_shift != 0)){
    							s[0] += 0x20; //大小写的转化
    						 }
    				}
    				if( s[0] != 0)//一般字符
    				{
    					if(key_to == 0){
    						//发送给任务a
    						if( cursor_x < 128){
    							//显示一个字符光标就向后移动一次
    							s[1] = 0;
    							putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_C6C6C6, s, 1);
    							cursor_x += 8;
    						}
    					}else{
    						//发送给命令行
    						fifo32_put(&task_cons->fifo, s[0] + 256);
    					}
    				}
    					if(i == 256 + 0x0e ) //退格键
    					{//用空格把光标消去后移动一次
    					    if(key_to == 0){
    							if(cursor_x > 8){
    								putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
    								cursor_x -= 8;
    							}
    						}else{
    							fifo32_put(&task_cons->fifo, 8 + 256);//z这里定义在console中退格键的编码为8
    						}
    					}
    					if(i == 256 + 0x0f){//tab键
    					    if(key_to == 0){//通过0, 1 来决定将哪一个标题栏显示,哪一个变成灰色
    							key_to = 1;
    							make_wtitle8(buf_win,  sht_win->bxsize,  "task_a", 0);
    							make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1);
    						}else{
    							key_to = 0;
    							make_wtitle8(buf_win,  sht_win->bxsize,  "task_a", 1);
    							make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0);
    						}
    						sheet_refresh(sht_win,	0,	0, sht_win->bxsize,  21);
    						sheet_refresh(sht_cons,	0,	0, sht_cons->bxsize, 21);
    					}
    					if(i == 256 + 0x2a){//左shift on
    						key_shift |= 1;
    					}
    					if(i == 256 + 0x36){//右shift on
    						key_shift |= 2;
    					}
    					if(i == 256 + 0xaa){//左shift off
    						key_shift &= ~1;
    					}
    					if(i == 256 + 0xb6){//右shift off
    						key_shift &= ~2;
    					}
    				    if (i == 256 + 0x3a) {	/* CapsLock */
    					key_leds ^= 4;
    					fifo32_put(&keycmd, KEYCMD_LED);
    					fifo32_put(&keycmd, key_leds);
    				    }
    				    if (i == 256 + 0x45) {	/* NumLock */
    					key_leds ^= 2;
    					fifo32_put(&keycmd, KEYCMD_LED);
    					fifo32_put(&keycmd, key_leds);
    				    }
    				    if (i == 256 + 0x46) {	/* ScrollLock */
    				 	key_leds ^= 1;
    					fifo32_put(&keycmd, KEYCMD_LED);
    					fifo32_put(&keycmd, key_leds);
    				   }
    				   if(i == 256 + 0xfa){//键盘成功接收数据
    					keycmd_wait = -1;
    				   }
    				   if(i == 256 + 0xfe){//键盘为成功接收数据
    					wait_KBC_sendready();
    					io_out8(PORT_KEYDAT, keycmd_wait);
    				   }
    					//光标在显示
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    具体效果如图所示:
    在这里插入图片描述


    总结

    至此,今天我们完成了闲置任务的创建,以及命令行窗口的初步建造,接下来我们将进行逐步的完善,敬请期待!

  • 相关阅读:
    基于JavaWeb的汽车在线租赁管理系统
    Js进行base64编码、解码、中文乱码
    vRealize Operations Manager 安全补丁修复
    ant-design 雷达图 radar
    理解DDD设计
    Qt: windows下关闭系统窗体
    RedisJava基础代码实现
    从 12K 到 60K, 这 2023Java 研发必问高级面试题,过关斩将拿 offer
    保健品行业正在升级,你准备好了吗?
    每日一练--IT冷知识&C/C++--第二天
  • 原文地址:https://blog.csdn.net/qq_43696276/article/details/126093313