這裏演示一下 8052 console interface 的做法,包含解析 ANSI escape code 的做法。
原始碼下載void console_init(void)
{
g_cmd_line[0] = 0;
g_ansi_mode = 0;
g_position = 0;
printf_small("\033[2J");
printf_small("\033[H");
printf_small("\r\n # ");
}
void console_process(void)
{
char ch=getchar();
if (g_ansi_mode) {
ch = fp_parse_ansi(ch);
}
switch (ch) {
case '\r':
if (g_position > 0) {
console_parse();
g_position = 0;
}
printf_small("\r\n # ");
break;
case 0x07: /* beep */
putchar(ch);
break;
case '\t': /* tab */
break;
case '\b': /* backspace */
case 0x7f: /* delete */
delete_char();
break;
case '\033':/* escape */
g_ansi_mode = 1;
fp_parse_ansi = parse_ansi;
break;
default:
if (isprint(ch)) {
putchar(ch);
insert_char(ch);
}
}
}
void console_parse(void)
{
char cmid;
char *next;
g_cmd_line[g_position] = 0;
next = parse_command(&cmid, g_cmd_line, g_main_command);
switch (cmid) {
case -1: // null string
printf_small(c_return);
break;
case CMID_HELP:
printf_small("\n\r\tHELP\t\t\thelp message");
printf_small("\n\r\tDUMP [addr] [len]\tdump code data");
break;
case CMID_DUMP:
dump_codedata(next);
break;
default:
printf_small(c_error);
break;
}
}
char *parse_command(char *cmid, char *src, struct s_cmd *command)
{
char i;
char *cmd, *next;
// check null string
cmd = clear_space(src);
if (*cmd == 0) {
*cmid = -1;
return src;
}
// get command id
next = next_string(cmd);
for (i=0; command->cmd_id != CMID_MAX; i++) {
if (strcmp(cmd, command->cmd_string) == 0) break;
command++;
}
*cmid = command->cmd_id;
return next;
}
char *next_string(char *next)
{
while (*next) {
if (*next == ' ') break;
next++;
}
if (*next == ' ') {
*next = 0;
next++;
}
return next;
}
char *clear_space(char *src)
{
while (*src) {
if (*src != ' ') break;
src++;
}
return src;
}
char parse_ansi(char ch)
{
if (ch == 'O') {
fp_parse_ansi = parse_func;
}
else if (ch == '[') {
fp_parse_ansi = parse_bracket;
}
else {
return 0x07;
}
return 0;
}
char parse_bracket(char ch)
{
if (isdigit(ch)) {
g_ansi_digit = ch - '0';
fp_parse_ansi = parse_digit;
return 0;
}
// parse bracket
g_ansi_mode = 0;
switch (ch) {
case 'A': // move up
case 'B': // move down
break;
case 'C': // move right
putchar(' ');
insert_char(' ');
break;
case 'D': // move left
delete_char();
break;
default:
return 0x07;
}
return 0;
}
char parse_func(char ch)
{
g_ansi_mode = 0;
switch (ch) {
case 'P': /* F1 */
case 'Q': /* F2 */
case 'R': /* F3 */
case 'S': /* F4 */
break;
default:
return 0x07;
}
return 0;
}
char parse_digit(char ch)
{
if (ch != 0x7e) {
if (isdigit(ch)) {
g_ansi_digit = g_ansi_digit * 10 + ch - '0';
return 0;
}
else {
g_ansi_mode = 0;
return 0x07;
}
}
// parse digit
g_ansi_mode = 0;
switch (g_ansi_digit) {
case 1: /* home */
g_position = 0;
puts("\r # ");
puts("\033[K");
break;
case 3: /* delete */
delete_char();
break;
case 11: /* F1 */
case 24: /* F12 */
break;
default:
return 0x07;
}
return 0;
}
原始碼下載
全域變數
- char g_cmd_line[SZ_CMD_LINE+1];
記錄指令輸入的暫存字串,SZ_CMD_LINE 不可大於 128。 - char g_position;
記錄游標位置。 - char g_ansi_digit;
記錄 ANSI escape code 的數字部位。 - bit g_ansi_mode;
記錄是否進入 ANSI escape sequence 解析模式。 - char (*fp_parse_ansi)(char escape);
記錄使用 ANSI 解析的函數。
console init
- 清除營幕所有東西,並回到左上角的位置,最後顯示提示字元。
console routine process
- 讀取輸入字元。
- 進入 ANSI escape code parse 或解析輸入字元。
- '\r': 輸入完成,解析輸入字串。
- 0x07: beep char,輸出錯誤嗚叫聲。
- '\t': 忽略定位字元。
- '\b', 0x7f: 刪除字元。
- '\033': 進入 ANSI escape sequence mode。
- default: 記錄字元並顯示在營幕上。
console parse
- 取得 command id,並依 command id 執行相關程式。
parse command
- 取得 command id,並回傳下一個參數字串指標。
next string
- 取得參數字串並補上 \0 字元,並回傳下一個參數字串指標。
clear space
- 清除空白字元,並回傳參數字串指標。
parse ansi code
- 解析 ANSI escape code 第一個字元。
parse bracket
- 解析 ANSI escape code 第二個字元。
parse bracket
- 解析 ANSI escape code 第二個字元,這一個函數是針對 windows 的超級終端機所做的,標準 ANSI escape code 好像沒有。
parse bracket
- 解析 ANSI escape code 數字。
張貼留言