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

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

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

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



一、设置闲置任务

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

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

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

然后进一步的修改一下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;
}

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

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

在这里插入图片描述
发现确实可行,任务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);

修改窗口的函数:
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);
			}
		}
	}
}

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

在这里插入图片描述

能够象征性的切换窗口

这里我们的目的主要就,当我们按下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;
}

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

					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);
					}

然后,运行,按下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;
};

而后,修改一下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);
		}
	}
}

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

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);
					}

然后,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
	};

然后,我们更改主函数中的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;
					}
					//光标在显示
					光标代码!!!

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

显示大小写字母

要想区分开大小写的字母,需要我们同时对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);
				   }
					//光标在显示

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


总结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值