将光标移动到C程序中

Rol*_*iza 14 c linux shell

我想在C程序中向前和向后移动光标.我正在循环中读取整行,但我想如果按下光标键,屏幕上的光标会改变位置,而不会阻塞循环.我试过getwch()但它会阻止来电者,直到它被按下.我正在寻找的是类似于bash提示的行为.我正在阅读类似于此的代码:

while (TRUE) {
   printf("%s", PROMPT);
   fgets(input, 1024, stdin);
   do_something(input);
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试上面的函数readline(PROMPT)readline.h库上工作

Dav*_*eri 13

使用termios和控制台代码(VT100兼容 - 不可移植):

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

#define cursorforward(x) printf("\033[%dC", (x))
#define cursorbackward(x) printf("\033[%dD", (x))

#define KEY_ESCAPE  0x001b
#define KEY_ENTER   0x000a
#define KEY_UP      0x0105
#define KEY_DOWN    0x0106
#define KEY_LEFT    0x0107
#define KEY_RIGHT   0x0108

static struct termios term, oterm;

static int getch(void);
static int kbhit(void);
static int kbesc(void);
static int kbget(void);

static int getch(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 1;
    term.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    return c;
}

static int kbhit(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    if (c != -1) ungetc(c, stdin);
    return ((c != -1) ? 1 : 0);
}

static int kbesc(void)
{
    int c;

    if (!kbhit()) return KEY_ESCAPE;
    c = getch();
    if (c == '[') {
        switch (getch()) {
            case 'A':
                c = KEY_UP;
                break;
            case 'B':
                c = KEY_DOWN;
                break;
            case 'C':
                c = KEY_LEFT;
                break;
            case 'D':
                c = KEY_RIGHT;
                break;
            default:
                c = 0;
                break;
        }
    } else {
        c = 0;
    }
    if (c == 0) while (kbhit()) getch();
    return c;
}

static int kbget(void)
{
    int c;

    c = getch();
    return (c == KEY_ESCAPE) ? kbesc() : c;
}

int main(void)
{
    int c;

    while (1) {
        c = kbget();
        if (c == KEY_ENTER || c == KEY_ESCAPE || c == KEY_UP || c == KEY_DOWN) {
            break;
        } else
        if (c == KEY_RIGHT) {
            cursorbackward(1);
        } else
        if (c == KEY_LEFT) {
            cursorforward(1);
        } else {
            putchar(c);
        }
    }
    printf("\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


小智 9

使用ANSI转义序列的简单示例:

#include <stdio.h>


int main()
{
    char *string = "this is a string";
    char input[1024] = { 0 };
    printf("%s", string);
    /* move the cursor back 5 spaces */
    printf("\033[D");
    printf("\033[D");
    printf("\033[D");
    printf("\033[D");
    printf("\033[D");
    fgets(input, 1024, stdin);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为了做非常有用的终端需要使用termios.h和/或curses.h/ncurses.h进入规范模式.这样,可以立即捕获并响应退格键代码,并相应地将缓冲区绘制到屏幕.以下是如何将终端设置为规范模式的示例tcsetattr():

struct termios info;
tcgetattr(0, &info);
info.c_lflag &= ~ICANON;
info.c_cc[VMIN] = 1;
info.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &info);
Run Code Online (Sandbox Code Playgroud)

另一种选择可能是使用readline()editline()库.要使用readline库,请为编译器指定-lreadline.可以使用以下代码片段进行编译

cc -lreadline some.c -o some


#include <stdio.h>

#include <readline/readline.h>
#include <readline/history.h>

int main()
{
    char *inpt;
    int i = 0;

    while ( i < 10 )
    {
        inpt = readline("Enter text: ");
        add_history(inpt);
        printf("%s", inpt);
        printf("\n");
        ++i;
    }
    return 0;
Run Code Online (Sandbox Code Playgroud)

}