C中的箭头导航输入

时间:2016-04-05 09:44:53

标签: c termios

我正在为程序创建一个shell接口,起初我使用getline结合strtok来分割用户条目,但这不是一个很好的选择,因为如果引用了一个带引号的字符串,它将是在多个参数中分割,或者如果引用的字符串中存在空格,它们将被忽略。此外,我想实现shell的一些基本功能,如快捷方式Ctrl-L,用于清除shell。

所以我决定使用termios并以shell方式创建我自己的输入函数。

现在代码看起来像

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>


char *read_cmdline() {
    struct termios oldt;
    struct termios newt;
    tcgetattr(STDIN_FILENO, &oldt); /*store old settings */
    newt = oldt; /* copy old settings to new settings */
    newt.c_lflag &= ~(ICANON | ECHO); /* make one change to old settings in new settings */
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); /*apply the new settings immediatly */

   char *line = malloc(128); 
   int end_of_line = 0;
   char c, y, z;
   unsigned lus = 0;
   unsigned size = 128;

   while (!end_of_line) {

       if (lus+1 == size) {
           size *= 2;
           line = realloc(line, size);
       }

       c = getc(stdin);

       switch (c)
       {
           case 27:
               y = getchar();
               switch (y)
               {
                   case 91:
                       z = getchar();
                       switch (z)
                       {
                           case 65:
                               printf("up arrow key pressed\n");
                               continue;

                           case 66:
                               printf("down arrow key pressed\n");
                               continue;

                           case 67:
                               printf("right arrow key pressed\n");
                               continue;

                           case 68:
                               printf("left arrow key pressed\n");
                               continue;
                       }
                       break;
               }
           case 12:
               system("clear");
               break;
       }
       if (c  >= 32 && c <= 126) {
           putchar(c);
           line[lus++] = c;
       }
       else if (c == 13)
           end_of_line = 1;
   }
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /*reapply the old settings */
    return line;
}

尚未实现解析,只是实现了快捷Ctrl-L的基本字符串读取。

如何在字符串中进行左/右箭头导航?

编辑:我有一个实现,现在可以浏览一个sigle行,但是多行不能用于该代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>

#define MIN_SIZE 128
char *line = NULL;
static unsigned pos = 0;
static int size;
static int b_size;
static unsigned length = 0;
char *buff = NULL;
static unsigned b_pos = 0;
static unsigned b_length = 0;


void insert(char c)
{
    if (pos == length) {
        ++length;
        if (length == size) {
            size *= 2;
            line = realloc(line, size);
        }
        line[pos++] = c;
    }
    else {
        ++length;
        if (length == b_size) {
            b_size = size;
            size *= 2;
            buff = realloc(buff, size);
        }
        strncpy(buff, line, pos);
        strncpy(&buff[pos+1], &line[pos], length-pos);
        buff[pos++] = c;
        char *temp = buff;
        buff = line;
        line = temp;
    }
}

int move_cursor(int delta) {
    int pos2 = pos + delta;
    if (pos2 >= 0 && pos2 <= length) {
        pos = pos2;
        return 1;
    }
    else
        return 0;
}

int backspace() {
    if (pos == 0)
        return 0;
    else {
        strncpy(&line[pos-1], &line[pos], length - pos);
        --pos;
        --length;
        return 1;
    }
}

int suppr() {
    if (pos == length)
        return 0;
    else {
        strncpy(&line[pos], &line[pos+1], length-pos);
        --length;
    }
}

char *read_cmdline() {
    if (line == NULL) 
        line = malloc(MIN_SIZE);
    if (buff == NULL)
        buff = malloc(MIN_SIZE);
    struct termios oldt;
    struct termios newt;
    tcgetattr(STDIN_FILENO, &oldt); /*store old settings */
    newt = oldt; /* copy old settings to new settings */
    newt.c_lflag &= ~(ICANON | ECHO); /* make one change to old settings in new settings */
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); /*apply the new settings immediatly */

   int end_of_line = 0;
   char c, y, z;

   while (!end_of_line) {

       c = getc(stdin);

       switch (c)
       {
           case 127:
               backspace();
               putchar('\b');
           case 27:
               y = getchar();
               switch (y)
               {
                   case 91:
                       z = getchar();
                       switch (z)
                       {
                           case 65:
                               printf("up arrow key pressed\n");
                               continue;

                           case 66:
                               printf("down arrow key pressed\n");
                               continue;

                           case 67:
                               printf("right arrow key pressed\n");
                               continue;

                           case 68:
                               printf("\033[1D");
                               move_cursor(-1);
                               continue;
                       }
                       break;
               }
           case 12:
               system("clear");
               break;
       }
       if (c  >= 32 && c <= 126) {
           insert(c);
           printf("\033[%dD", length);
           printf("%s", line);
           if (pos < length)
               printf("\033[%dD", length-pos);
       }
       else if (c == 13)
           end_of_line = 1;
   }
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /*reapply the old settings */
    return line;
}

问题是我如何在while循环中实现打印,我应该恢复终端大小并打印到这个大小...这是一个棘手的问题!我没有提到我不想在我的项目中添加依赖项,因此不允许使用ncurses,但它是一个UNIX项目,所以不需要平台兼容性。 (是curses标准吗?)

0 个答案:

没有答案