boot中的行编辑功能
来源:互联网 发布:画平面示意图软件 编辑:程序博客网 时间:2024/05/29 08:06
一 行编辑的由来
在和程序交互的过程中,用户输入难免会出错,如果不小心键入失误而不能修改,那该是一种很不友好的体验,于是行编辑出现了,用户在输入过程中可以删除,粘贴,移动光标,在光标处插入,可以翻看历史命令,只有当用户确认输入是正确无误,才按回车将输入结果提交给程序。
如果行编辑功能由用户程序来实现,那么将增加用户程序编程的难度,而且很多行编辑功能基本是相似的,于是linux就把它放在了内核中,也就是常说的行规程(line discipline), 终端类型不同,对应的line discipline也不一样,用户进程每次通过tty读取line discipline处理后的一行数据,另外用户也可以通过termios配置line discipline的行为,当然了这种配置是有限的,如果用户程序希望定制自己特有的行编辑功能,如一些编辑软件vi,shell等等,可以将tty设置为raw模式,这将跳过line discipline处理直接读取输入的原始值,而将行编辑功能交由特定的用户程序来处理,如readline库就是其中一个使用非常广泛的处理行编辑的开源库。
本文主要讲解boot中行编辑功能的实现,功能较简单。
二 行编辑的实现
#define CTRL(x) ((x)-'@')#define VKEY(x)(0x100|(x))#define VKEY_UPVKEY(1)#define VKEY_DOWNVKEY(2)#define VKEY_LEFTVKEY(3)#define VKEY_RIGHTVKEY(4)#define VKEY_PGUPVKEY(5)#define VKEY_PGDNVKEY(6)#define VKEY_HOMEVKEY(7)#define VKEY_ENDVKEY(8)#define VKEY_F1VKEY(0x10)#define VKEY_F2VKEY(0x11)#define VKEY_F3VKEY(0x12)#define VKEY_F4VKEY(0x13)#define VKEY_F5VKEY(0x14)#define VKEY_F6VKEY(0x15)#define VKEY_F7VKEY(0x16)#define VKEY_F8VKEY(0x17)#define VKEY_F9VKEY(0x18)#define VKEY_F10VKEY(0x19)#define VKEY_F11VKEY(0x1A)#define VKEY_F12VKEY(0x1B)#define VKEY_ESC27int console_readline(char *prompt,char *str,int maxlen){ int reading = 1; int ch; int idx = 0; int len = 0; int t; int klen; int recall; int nosave = 0; char *x; char env[10]; console_inreadline++; recall = console_nextsave; if (console_savedlines[console_nextsave]) {KFREE(console_savedlines[console_nextsave]);console_savedlines[console_nextsave] = NULL;} console_savedlines[console_nextsave] = strdup(""); if (prompt && *prompt) console_write(prompt,strlen(prompt)); POLL(); while (reading) {/* * If someone used console_log (above) or hit Control-C (below), * redisplay the prompt and the string we've got so far. */if (console_redisplay) { if (prompt && *prompt) console_write(prompt,strlen(prompt)); console_write(str,idx); console_redisplay = 0; continue; }/* * if nobody's typed anything, keep polling */if (console_status() == 0) { POLL(); continue; }/* * Get the char from the keyboard */ch = console_readkey();if (ch < 0) break;if (ch == 0) continue;/* * And dispatch it. Lots of yucky character manipulation follows */switch (ch) { case CTRL('C'):/* Ctrl-C - cancel line */console_write("^C\r\n",4);console_redisplay = 1;nosave = 1;idx = 0;len = 0;break; case 0x7f:/* Backspace, Delete */ case CTRL('H'):if (idx > 0) { nosave = 0; len--; idx--; console_write("\b",1); if (len != idx) {for (t = idx; t < len; t++) str[t] = str[t+1];console_write(&str[idx],len-idx);console_whiteout(1);console_backspace(len-idx);} else {console_whiteout(1);} }break; case CTRL('D'):/* Ctrl-D */if ((idx > 0) && (len != idx)) { nosave = 0; len--; for (t = idx; t < len; t++) str[t] = str[t+1]; console_write(&str[idx],len-idx); console_whiteout(1); console_backspace(len-idx); }break; case CTRL('B'):/* cursor left */ case VKEY_LEFT:if (idx > 0) { idx--; console_backspace(1); }break; case CTRL('F'):/* cursor right */ case VKEY_RIGHT:if (idx < len) { console_write(&str[idx],1); idx++; }break; case CTRL('A'):/* cursor to BOL */console_backspace(idx);idx = 0;break; case CTRL('E'):/* cursor to EOL */if (len-idx > 0) console_write(&str[idx],len-idx);idx = len;break; case CTRL('K'):/* Kill to EOL */if (idx != len) { str[len] = '\0'; if (console_killbuffer) KFREE(console_killbuffer); console_killbuffer = strdup(&str[idx]); console_whiteout(len-idx); len = idx; nosave = 0; }break; case CTRL('Y'):/* Yank killed data */if (console_killbuffer == NULL) break;klen = strlen(console_killbuffer);if (klen == 0) break;if (len + klen > maxlen) break;nosave = 0;for (t = len + klen; t > idx; t--) { str[t-1] = str[t-klen-1]; }for (t = 0; t < klen; t++) str[t+idx] = console_killbuffer[t];len += klen;console_write(&str[idx],len-idx);idx += klen;console_backspace(len-idx-1);break; case CTRL('R'):/* Redisplay line */str[len] = 0;console_crlf();if (prompt && *prompt) console_write(prompt,strlen(prompt));console_write(str,len);console_backspace(len-idx);break; case CTRL('U'):/* Cancel line */console_backspace(idx);console_eraseeol();if (len > 0) nosave = 1;idx = 0;len = 0;break; case CTRL('M'):/* terminate */ case CTRL('J'):console_crlf();reading = 0;break; case CTRL('P'): case VKEY_UP:/* recall previous line */t = recall;t--;if (t < 0) t = MAXSAVELINES-1;if (console_savedlines[t] == NULL) break;recall = t;console_backspace(idx);strcpy(str,console_savedlines[recall]);len = idx = strlen(console_savedlines[recall]);console_eraseeol();console_write(str,len);nosave = 1;break; case CTRL('N'): case VKEY_DOWN:/* Recall next line */t = recall; t++;if (t == MAXSAVELINES) t = 0;if (console_savedlines[t] == NULL) break;recall = t;console_backspace(idx);strcpy(str,console_savedlines[recall]);len = idx = strlen(console_savedlines[recall]);console_eraseeol();console_write(str,len);nosave = 1;break; case VKEY_F1: case VKEY_F2: case VKEY_F3: case VKEY_F4: case VKEY_F5: case VKEY_F6: case VKEY_F7: case VKEY_F8: case VKEY_F9: case VKEY_F10: case VKEY_F11: case VKEY_F12:sprintf(env,"F%d",ch-VKEY_F1+1);x = env_getenv(env);if (x) { console_backspace(idx); strcpy(str,x); idx = len = strlen(str); console_eraseeol(); console_write(str,len); console_crlf(); reading = 0; nosave = 1; }/* * If F12 is undefined, it means "repeat last command" */if (ch == VKEY_F12) { t = recall; t--; if (t < 0) t = MAXSAVELINES-1; if (console_savedlines[t] == NULL) break; recall = t; console_backspace(idx); strcpy(str,console_savedlines[recall]); len = idx = strlen(console_savedlines[recall]); console_eraseeol(); console_write(str,len); console_crlf(); reading = 0; nosave = 1; }break; default:/* insert character */if (ch >= ' ') { if (idx < (maxlen-1)) {nosave = 0;for (t = len; t > idx; t--) { str[t] = str[t-1]; }str[idx] = ch;len++;if (len != idx) { if(g_enable_printf) /*------skyworth add*/ { console_write(&str[idx],len-idx); } console_backspace(len-idx-1); }idx++;} }break; }} POLL(); console_inreadline--; str[len] = 0; if ((len != 0) && !nosave) {if (console_savedlines[console_nextsave]) { KFREE(console_savedlines[console_nextsave]); }console_savedlines[console_nextsave] = strdup(str);console_nextsave++;if (console_nextsave == MAXSAVELINES) console_nextsave = 0;} return len;}int console_readkey(void){ unsigned char ch; int num; GETCHAR(ch); switch (ch) {case VKEY_ESC: GETCHAR(ch); switch (ch) {case 'O': GETCHAR(ch); switch (ch) {case 'P': return VKEY_F1;case 'Q': return VKEY_F2;case 'R': return VKEY_F3;case 'S': return VKEY_F4;} return (int)ch;case '[': GETCHAR(ch); if ((ch >= '0') && (ch <= '9')) {console_readnum(&num,&ch);if (ch == '~') { switch (num) {case 2: return VKEY_HOME;case 3: return VKEY_PGUP;case 5: if (console_mode == XTERM) return VKEY_PGUP; return VKEY_END;case 6: if (console_mode == XTERM) return VKEY_PGDN; return VKEY_PGDN;case 11: return VKEY_F1;case 12: return VKEY_F2;case 13: return VKEY_F3;case 14: return VKEY_F4;case 15: return VKEY_F5;case 17: return VKEY_F6;case 18: return VKEY_F7;case 19: return VKEY_F8;case 20: return VKEY_F9;case 21: return VKEY_F10;case 23: return VKEY_F11;case 24: return VKEY_F12;} return (int)ch; }} else {switch (ch) { case 'A':return VKEY_UP; case 'B':return VKEY_DOWN; case 'C':return VKEY_RIGHT; case 'D':return VKEY_LEFT; case 'F':return VKEY_HOME; case 'H':return VKEY_END; default:return (int) ch; }}default: return (int)ch;}default: return (int) ch;}}static void console_readnum(int *num,unsigned char *ch){ int total = 0; for (;;) {total = (total * 10) + (*ch - '0');while (console_read(ch,1) != 1) { POLL(); }if (!((*ch >= '0') && (*ch <= '9'))) break;} *num = total;}static void console_backspace(int n){ int t; for (t = 0; t < n; t++) console_write("\b",1);}static void console_whiteout(int n){ int t; for (t = 0; t < n; t++) console_write(" ",1); for (t = 0; t < n; t++) console_write("\b",1);}static void console_eraseeol(void){ console_write("\033[K",3);}static void console_crlf(void){ console_write("\r\n",2);}
上述代码我就不做过多解释了,一看就会明白,这里主要提一下console_readkey(), 为啥返回的是Int型而不是char型呢,这主要涉及到转义序列, 普通字符直接转化为int返回了
len为输入的总的字符数,idx为当前光标所在的位置,console_write()用于回显和光标的移动
阅读全文
0 0
- boot中的行编辑功能
- dataGrid中的行编辑功能
- TableView中的编辑删除功能
- 问卷调查功能中的题目编辑功能
- UITableViewController 编辑功能中的,添加,删除,修改
- UITableViewController 编辑功能中的,添加,删除,修改
- UITableViewController 编辑功能中的,添加,删除,修改
- jqgrid实现行编辑功能
- easyui datagrid 行编辑功能
- ui-grid 行编辑功能
- ArcGIS Server .Net ADF中的编辑功能(一)
- 在MVC中的功能化编辑(ASP.NET)
- MDuiLib界面编辑器中的图片编辑功能相关
- sublime text中的一些快速编辑技巧以及服务器功能
- listview中的长按item编辑功能的解析
- 二十四、UI-Grid 行编辑功能
- [转载]easyui datagrid 行内编辑功能
- AE开发编辑功能
- PHP修改图片颜色(生成彩色二维码)
- TextView实现跑马灯的效果;
- HTML5 绘制2D图像
- Canvas API
- Markdown Editor
- boot中的行编辑功能
- Android自定义类关闭所有活动实现退出
- HTML5 Storage
- 灌水(python实现)
- 利用JMeter的Java请求采样器进行rpc接口的性能测试
- javascript addEventListener讲解
- 求1-100内能被3整除,不能被5整除的数字。
- 实例:python图像处理(Pillow+numpy)
- Java文件下载的几种方式