?? console.c.bak
字號:
// 若當前光標處在行末端或末端以外,則將光標移到下行頭列。并調整光標位置對應的內存指針pos。 if (x >= video_num_columns) { x -= video_num_columns; pos -= video_size_row; lf (); }// 將字符c 寫到顯示內存中pos 處,并將光標右移1 列,同時也將pos 對應地移動2 個字節。//__asm__ ("movb _attr,%%ah\n\t" "movw %%ax,%1\n\t"::"a" (c), "m" (*(short *) pos):"ax");
_asm {
mov al,c;
mov ah,attr;
mov ebx,pos
mov [ebx],ax;
}
pos += 2; x++;// 如果字符c 是轉義字符ESC,則轉換狀態state 到1。 } else if (c == 27) state = 1;// 如果字符c 是換行符(10),或是垂直制表符VT(11),或者是換頁符FF(12),則移動光標到下一行。 else if (c == 10 || c == 11 || c == 12) lf ();// 如果字符c 是回車符CR(13),則將光標移動到頭列(0 列)。 else if (c == 13) cr ();// 如果字符c 是DEL(127),則將光標右邊一字符擦除(用空格字符替代),并將光標移到被擦除位置。 else if (c == ERASE_CHAR (tty)) del ();// 如果字符c 是BS(backspace,8),則將光標右移1 格,并相應調整光標對應內存位置指針pos。 else if (c == 8) { if (x) { x--; pos -= 2; }// 如果字符c 是水平制表符TAB(9),則將光標移到8 的倍數列上。若此時光標列數超出屏幕最大列數,// 則將光標移到下一行上。 } else if (c == 9) { c = (char)(8 - (x & 7)); x += c; pos += c << 1; if (x > video_num_columns) { x -= video_num_columns; pos -= video_size_row; lf (); } c = 9;// 如果字符c 是響鈴符BEL(7),則調用蜂鳴函數,是揚聲器發聲。 } else if (c == 7) sysbeep (); break;// 如果原狀態是0,并且字符是轉義字符ESC(0x1b = 033 = 27),則轉到狀態1 處理。 case 1: state = 0;// 如果字符c 是'[',則將狀態state 轉到2。 if (c == '[') state = 2;// 如果字符c 是'E',則光標移到下一行開始處(0 列)。 else if (c == 'E') gotoxy (0, y + 1);// 如果字符c 是'M',則光標上移一行。 else if (c == 'M') ri ();// 如果字符c 是'D',則光標下移一行。 else if (c == 'D') lf ();// 如果字符c 是'Z',則發送終端應答字符序列。 else if (c == 'Z') respond (tty);// 如果字符c 是'7',則保存當前光標位置。注意這里代碼寫錯!應該是(c=='7')。 else if (x == '7') save_cur ();// 如果字符c 是'8',則恢復到原保存的光標位置。注意這里代碼寫錯!應該是(c=='8')。 else if (x == '8') restore_cur (); break;// 如果原狀態是1,并且上一字符是'[',則轉到狀態2 來處理。 case 2:// 首先對ESC 轉義字符序列參數使用的處理數組par[]清零,索引變量npar 指向首項,并且設置狀態// 為3。若此時字符不是'?',則直接轉到狀態3 去處理,否則去讀一字符,再到狀態3 處理代碼處。 for (npar = 0; npar < NPAR; npar++) par[npar] = 0; npar = 0; state = 3; if (ques = (c == '?')) break;// 如果原來是狀態2;或者原來就是狀態3,但原字符是';'或數字,則在下面處理。 case 3:// 如果字符c 是分號';',并且數組par 未滿,則索引值加1。 if (c == ';' && npar < NPAR - 1) { npar++; break;// 如果字符c 是數字字符'0'-'9',則將該字符轉換成數值并與npar 所索引的項組成10 進制數。 } else if (c >= '0' && c <= '9') { par[npar] = 10 * par[npar] + c - '0'; break;// 否則轉到狀態4。 } else state = 4;// 如果原狀態是狀態3,并且字符不是';'或數字,則轉到狀態4 處理。首先復位狀態state=0。 case 4: state = 0; switch (c) {// 如果字符c 是'G'或'`',則par[]中第一個參數代表列號。若列號不為零,則將光標右移一格。 case 'G': case '`': if (par[0]) par[0]--; gotoxy (par[0], y); break;// 如果字符c 是'A',則第一個參數代表光標上移的行數。若參數為0 則上移一行。 case 'A': if (!par[0]) par[0]++; gotoxy (x, y - par[0]); break;// 如果字符c 是'B'或'e',則第一個參數代表光標下移的行數。若參數為0 則下移一行。 case 'B': case 'e': if (!par[0]) par[0]++; gotoxy (x, y + par[0]); break;// 如果字符c 是'C'或'a',則第一個參數代表光標右移的格數。若參數為0 則右移一格。 case 'C': case 'a': if (!par[0]) par[0]++; gotoxy (x + par[0], y); break;// 如果字符c 是'D',則第一個參數代表光標左移的格數。若參數為0 則左移一格。 case 'D': if (!par[0]) par[0]++; gotoxy (x - par[0], y); break;// 如果字符c 是'E',則第一個參數代表光標向下移動的行數,并回到0 列。若參數為0 則下移一行。 case 'E': if (!par[0]) par[0]++; gotoxy (0, y + par[0]); break;// 如果字符c 是'F',則第一個參數代表光標向上移動的行數,并回到0 列。若參數為0 則上移一行。 case 'F': if (!par[0]) par[0]++; gotoxy (0, y - par[0]); break;// 如果字符c 是'd',則第一個參數代表光標所需在的行號(從0 計數)。 case 'd': if (par[0]) par[0]--; gotoxy (x, par[0]); break;// 如果字符c 是'H'或'f',則第一個參數代表光標移到的行號,第二個參數代表光標移到的列號。 case 'H': case 'f': if (par[0]) par[0]--; if (par[1]) par[1]--; gotoxy (par[1], par[0]); break;// 如果字符c 是'J',則第一個參數代表以光標所處位置清屏的方式:// ANSI 轉義序列:'ESC [sJ'(s = 0 刪除光標到屏幕底端;1 刪除屏幕開始到光標處;2 整屏刪除)。 case 'J': csi_J (par[0]); break;// 如果字符c 是'K',則第一個參數代表以光標所在位置對行中字符進行刪除處理的方式。// ANSI 轉義字符序列:'ESC [sK'(s = 0 刪除到行尾;1 從開始刪除;2 整行都刪除)。 case 'K': csi_K (par[0]); break;// 如果字符c 是'L',表示在光標位置處插入n 行(ANSI 轉義字符序列'ESC [nL')。 case 'L': csi_L (par[0]); break;// 如果字符c 是'M',表示在光標位置處刪除n 行(ANSI 轉義字符序列'ESC [nM')。 case 'M': csi_M (par[0]); break;// 如果字符c 是'P',表示在光標位置處刪除n 個字符(ANSI 轉義字符序列'ESC [nP')。 case 'P': csi_P (par[0]); break;// 如果字符c 是'@',表示在光標位置處插入n 個字符(ANSI 轉義字符序列'ESC [n@')。 case '@': csi_at (par[0]); break;// 如果字符c 是'm',表示改變光標處字符的顯示屬性,比如加粗、加下劃線、閃爍、反顯等。// ANSI 轉義字符序列:'ESC [nm'。n = 0 正常顯示;1 加粗;4 加下劃線;7 反顯;27 正常顯示。 case 'm': csi_m (); break;// 如果字符c 是'r',則表示用兩個參數設置滾屏的起始行號和終止行號。 case 'r': if (par[0]) par[0]--; if (!par[1]) par[1] = video_num_lines; if (par[0] < par[1] && par[1] <= video_num_lines) { top = par[0]; bottom = par[1]; } break;// 如果字符c 是's',則表示保存當前光標所在位置。 case 's': save_cur (); break;// 如果字符c 是'u',則表示恢復光標到原保存的位置處。 case 'u': restore_cur (); break; } } }// 最后根據上面設置的光標位置,向顯示控制器發送光標顯示位置。 set_cursor ();}/** void con_init(void);* 這個子程序初始化控制臺中斷,其它什么都不做。如果你想讓屏幕干凈的話,就使用* 適當的轉義字符序列調用tty_write()函數。** 讀取setup.s 程序保存的信息,用以確定當前顯示器類型,并且設置所有相關參數。*/voidcon_init (void){ register unsigned char a; char *display_desc = "????"; char *display_ptr; video_num_columns = ORIG_VIDEO_COLS; // 顯示器顯示字符列數。 video_size_row = video_num_columns * 2; // 每行需使用字節數。 video_num_lines = ORIG_VIDEO_LINES; // 顯示器顯示字符行數。 video_page = (unsigned char)ORIG_VIDEO_PAGE; // 當前顯示頁面。 video_erase_char = 0x0720; // 擦除字符(0x20 顯示字符, 0x07 是屬性)。// 如果原始顯示模式等于7,則表示是單色顯示器。 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ { video_mem_start = 0xb0000; // 設置單顯映象內存起始地址。 video_port_reg = 0x3b4; // 設置單顯索引寄存器端口。 video_port_val = 0x3b5; // 設置單顯數據寄存器端口。// 根據BIOS 中斷int 0x10 功能0x12 獲得的顯示模式信息,判斷顯示卡單色顯示卡還是彩色顯示卡。// 如果使用上述中斷功能所得到的BX 寄存器返回值不等于0x10,則說明是EGA 卡。因此初始// 顯示類型為EGA 單色;所使用映象內存末端地址為0xb8000;并置顯示器描述字符串為'EGAm'。// 在系統初始化期間顯示器描述字符串將顯示在屏幕的右上角。 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { video_type = VIDEO_TYPE_EGAM; // 設置顯示類型(EGA 單色)。 video_mem_end = 0xb8000; // 設置顯示內存末端地址。 display_desc = "EGAm"; // 設置顯示描述字符串。 }// 如果BX 寄存器的值等于0x10,則說明是單色顯示卡MDA。則設置相應參數。 else { video_type = VIDEO_TYPE_MDA; // 設置顯示類型(MDA 單色)。 video_mem_end = 0xb2000; // 設置顯示內存末端地址。 display_desc = "*MDA"; // 設置顯示描述字符串。 } }// 如果顯示模式不為7,則為彩色模式。此時所用的顯示內存起始地址為0xb800;顯示控制索引寄存// 器端口地址為0x3d4;數據寄存器端口地址為0x3d5。 else /* If not, it is color. */ { video_mem_start = 0xb8000; // 顯示內存起始地址。 video_port_reg = 0x3d4; // 設置彩色顯示索引寄存器端口。 video_port_val = 0x3d5; // 設置彩色顯示數據寄存器端口。// 再判斷顯示卡類別。如果BX 不等于0x10,則說明是EGA 顯示卡。 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { video_type = VIDEO_TYPE_EGAC; // 設置顯示類型(EGA 彩色)。 video_mem_end = 0xbc000; // 設置顯示內存末端地址。 display_desc = "EGAc"; // 設置顯示描述字符串。 }// 如果BX 寄存器的值等于0x10,則說明是CGA 顯示卡。則設置相應參數。 else { video_type = VIDEO_TYPE_CGA; // 設置顯示類型(CGA)。 video_mem_end = 0xba000; // 設置顯示內存末端地址。 display_desc = "*CGA"; // 設置顯示描述字符串。 } }/* Let the user known what kind of display driver we are using *//* 讓用戶知道我們正在使用哪一類顯示驅動程序 */// 在屏幕的右上角顯示顯示描述字符串。采用的方法是直接將字符串寫到顯示內存的相應位置處。// 首先將顯示指針display_ptr 指到屏幕第一行右端差4 個字符處(每個字符需2 個字節,因此減8)。 display_ptr = ((char *) video_mem_start) + video_size_row - 8;// 然后循環復制字符串中的字符,并且每復制一個字符都空開一個屬性字節。 while (*display_desc) { *display_ptr++ = *display_desc++; // 復制字符。 display_ptr++; // 空開屬性字節位置。 }/* Initialize the variables used for scrolling (mostly EGA/VGA) *//* 初始化用于滾屏的變量(主要用于EGA/VGA) */ origin = video_mem_start; // 滾屏起始顯示內存地址。 scr_end = video_mem_start + video_num_lines * video_size_row; // 滾屏結束內存地址。 top = 0; // 最頂行號。 bottom = video_num_lines; // 最底行號。 gotoxy (ORIG_X, ORIG_Y); // 初始化光標位置x,y 和對應的內存位置pos。 set_trap_gate (0x21, &keyboard_interrupt); // 設置鍵盤中斷陷阱門。 outb_p ((unsigned char)(inb_p (0x21) & 0xfd), 0x21); // 取消8259A 中對鍵盤中斷的屏蔽,允許IRQ1。 a = inb_p (0x61); // 延遲讀取鍵盤端口0x61(8255A 端口PB)。 outb_p ((unsigned char)(a | 0x80), 0x61); // 設置禁止鍵盤工作(位7 置位), outb (a, 0x61); // 再允許鍵盤工作,用以復位鍵盤操作。}/* from bsd-net-2: *///// 停止蜂鳴。// 復位8255A PB 端口的位1 和位0。voidsysbeepstop (void){/* disable counter 2 *//* 禁止定時器2 */ outb ((unsigned char)(inb_p (0x61) & 0xFC), 0x61);}int beepcount = 0;// 開通蜂鳴。// 8255A 芯片PB 端口的位1 用作揚聲器的開門信號;位0 用作8253 定時器2 的門信號,該定時器的// 輸出脈沖送往揚聲器,作為揚聲器發聲的頻率。因此要使揚聲器蜂鳴,需要兩步:首先開啟PB 端口// 位1 和位0(置位),然后設置定時器發送一定的定時頻率即可。static voidsysbeep (void){/* enable counter 2 *//* 開啟定時器2 */ outb_p ((unsigned char)(inb_p (0x61) | 3), 0x61);/* set command for counter 2, 2 byte write *//* 送設置定時器2 命令 */ outb_p (0xB6, 0x43);/* send 0x637 for 750 HZ *//* 設置頻率為750HZ,因此送定時值0x637 */ outb_p (0x37, 0x42); outb (0x06, 0x42);/* 1/8 second *//* 蜂鳴時間為1/8 秒 */ beepcount = HZ / 8;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -