实现一个简单的行编辑器(优化)
0.目录
1.前言
2.使用方向键来实现光标左右移动
3.按两下ESC键退出程序
4.移动光标到行首
5.移动光标到行尾
6.总代码
1.前言
之前已经写过一篇文章了:实现一个简单的行编辑器
实现的功能有:
1.按下大小写字母或者数字的时候,显示在屏幕上
2.可以使用退格键来删除前一个字符
3.可以使用Del键来删除一行
4.使用'['键来实现光标左移
5.使用']'键来实现光标右移
但是还是有很多不完善的地方。本篇文章修改以及添加了以下功能:
1.使用方向键'←'键来实现光标左移
2.使用方向键'→'键来实现光标右移
3.按两下ESC键退出程序
4.使用'['键来实现移动光标到行首
5.使用']'键来实现移动光标到行尾
并且在之前的文章中,采用的是putchar('\b');
实现光标左移,使用输出当前字符实现光标右移。
在这篇文章中,将更改这种方法。
2.使用方向键来实现光标左右移动
在之前的文章中提到过。方向键其实是一次性输入了三个字符才组成的。
以下是对应关系:
上:0x1b 0x5b 0x41
下:0x1b 0x5b 0x42
左:0x1b 0x5b 0x44
右:0x1b 0x5b 0x43
Del键:0x1b 0x5b 0x33 0x7e
其中,0x41、0x42、0x43、0x44分别就是大写字母A、B、C、D。
在本篇文章中不实现上和下的功能。
//连续输出三个字符实现左移光标
putchar(0x1b);
putchar(0x5b);
putchar(0x44);
//连续输出三个字符实现右移光标
putchar(0x1b);
putchar(0x5b);
putchar(0x43);
在while循环中实现:
else if ( c == 0x1b )
{
c=getchar();
if ( c == 0x5b )
{
c=getchar();
if ( c == 0x44 && p )
{
//连续输出三个字符实现左移光标
putchar(0x1b);
putchar(0x5b);
putchar(0x44);
p--;
}
else if ( c == 0x43 && p < len )
{
//连续输出三个字符实现右移光标
putchar(0x1b);
putchar(0x5b);
putchar(0x43);
p++;
}
else continue;
}
else continue;
}
这里使用了一个叫做状态机的概念。
有兴趣的可以去找找相关的资料了解一下。
3.按两下ESC键退出程序
只需要在上面的程序中加入一段代码就行了。
顺便将Del键也改一下:
else if ( c == 0x1b )
{
c=getchar();
if ( c == 0x5b )
{
c=getchar();
if ( c == 0x44 && p )
{
//连续输出三个字符实现左移光标
putchar(0x1b);
putchar(0x5b);
putchar(0x44);
p--;
}
else if ( c == 0x43 && p < len )
{
//连续输出三个字符实现右移光标
putchar(0x1b);
putchar(0x5b);
putchar(0x43);
p++;
}
else if ( c == 0x33 )
{
c=getchar();
if ( c == 0x7e )
{
//删除键(Del):删除整行(user input delete)
//1.从光标处移动到结尾
while( ++p <= len )
putchar(' ');
//2.从结尾往前依次退格
while( --p )
fun_backspace();
//3.len置0
len = 0;
}
else continue;
}
else continue;
}
else if ( c == 0x1b )
{
//按了两次ESC键,退出程序
break;
}
else continue;
}
4.移动光标到行首
使用'['键来实现移动光标到行首
else if ( c == '[' && p )
{
//使用'['移动光标到行首
while( p-- )
fun_left();
p = 0;
}
5.移动光标到行尾
使用']'键来实现移动光标到行尾
else if ( c == ']' && p < len )
{
//使用']'移动光标到行尾
while( p++ < len )
fun_right();
p = len;
}
6.总代码
/* 设计完成一个行编辑器
* 能够接受用户输入,能倒退删除,插入,移动光标等
*/
#include <stdio.h>
#include <termios.h>
#define oops(s, x) { perror(s); exit(x); }
void fun_set(struct termios *info, char set);//设置回显位,设置缓冲
void fun_backspace();//实现退格功能
void fun_left();//实现光标左移
void fun_right();//实现光标右移
int main()
{
int c;
int i, j;
struct termios info;
fun_set( &info, 0 );//关掉回显位,关掉缓冲
char str[30];//保存输出的字符
int p = 0;//当前位置
int len = 0;//总长度
while( ( c=getchar() ) != EOF )
{
if( isalnum(c) )
{
//isalnum()函数:如果c是一个数字或字母返回非0值,否则为0
//user input a letter or a number
//1.将当前位置之后的值依次后移
j = ++len;
while( j-- > p )
str[j] = str[j-1];
str[p] = c;
j = len - p - 1;//光标要移动的距离
//2.从当前位置开始重新输出数组
while( p < len )
putchar(str[p++]);
//3.将光标移动到之前的位置
while( j-- > 0 && p-- )
fun_left();
}
else if( c == 0x7f && p )
{
//退格键(user input a backspace)
j = len - p;//光标要移动的距离
//1.将当前位置之后的值依次前移
putchar('\b');
while( p < len )
{
str[p-1] = str[p];
putchar(str[p]);
p++;
}
//2.将最后一个元素删除
putchar(' ');
putchar('\b');
len--;
p--;
//3.将光标移动到之前的位置
while( j-- > 0 && p-- )
fun_left();
}
else if ( c == 0x1b )
{
c=getchar();
if ( c == 0x5b )
{
c=getchar();
if ( c == 0x44 && p )
{
//连续输出三个字符实现左移光标
fun_left();
p--;
}
else if ( c == 0x43 && p < len )
{
//连续输出三个字符实现右移光标
fun_right();
p++;
}
else if ( c == 0x33 )
{
c=getchar();
if ( c == 0x7e )
{
//删除键(Del):删除整行(user input delete)
//1.从光标处移动到结尾
while( ++p <= len )
putchar(' ');
//2.从结尾往前依次退格
while( --p )
fun_backspace();
//3.len置0
len = 0;
}
else continue;
}
else continue;
}
else if ( c == 0x1b )
{
//按了两次ESC键,退出程序
break;
}
else continue;
}
else if ( c == '[' && p )
{
//使用'['移动光标到行首
while( p-- )
fun_left();
p = 0;
}
else if ( c == ']' && p < len )
{
//使用']'移动光标到行尾
while( p++ < len )
fun_right();
p = len;
}
}
fun_set( &info, 1 );//打开回显位,打开缓冲
}
void fun_set(struct termios *info, char set)
{
if ( tcgetattr(0, info) == -1 ) /* get attribs */
oops("tcgettattr", 1);
/*set为1,打开回显位,打开缓冲;set为0,关掉回显位,关掉缓冲*/
if( set )
{
(*info).c_lflag |= ECHO; /* turn on bit */
(*info).c_lflag &= ICANON; /* turn on bit */
}
else
{
(*info).c_lflag &= ~ECHO; /* turn off bit */
(*info).c_lflag &= ~ICANON; /* turn off bit */
}
if ( tcsetattr(0, TCSANOW, info) == -1 ) /* set attribs */
oops("tcsetattr",2);
}
void fun_backspace()
{
putchar('\b');
putchar(' ');
putchar('\b');
}
void fun_left()
{
putchar(0x1b);
putchar(0x5b);
putchar(0x44);
}
void fun_right()
{
putchar(0x1b);
putchar(0x5b);
putchar(0x43);
}