微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将光标移动到C程序中

我想在C程序中向前和向后移动光标。 我正在循环读整行,但我希望如果光标键被按下,屏幕上的光标将改变位置,而不会阻塞循环。 我尝试了getwch()但它阻止了调用者,直到它被按下。 我正在寻找的是一个类似于bash提示符的行为。 我正在阅读与此类似的代码

while (TRUE) { printf("%s",PROMPT); fgets(input,1024,stdin); do_something(input); }

我试图上面的函数像readline.h库readline(PROMPT)

用win32打开一个没有标题栏的窗口

C编程 – 使用pipe道处理stdout和stdin

为什么中断处理程序有睡眠function?

是否有可能从Windows的Windows服务发送Windows Toast通知

我怎么知道一个目录真的是一个回收站?

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

#include <stdio.h> #include <string.h> #include <termios.h> #include <unistd.h> #define cursorforward(x) printf("33[%dC",(x)) #define cursorbackward(x) printf("33[%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,&oterm); return c; } static int kbhit(void) { int c = 0; tcgetattr(0,sizeof(term)); term.c_lflag &= ~(ICANON | ECHO); term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 1; tcsetattr(0,&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; }

使用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("33[D"); printf("33[D"); printf("33[D"); printf("33[D"); printf("33[D"); fgets(input,stdin); return 0; }

为了做到非常有用,终端需要使用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,&info);

一个选择可能是使用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;

}

左右移动光标。 停止输入新行或太多的字符

#include <stdio.h> #include <string.h> #include <termios.h> #include <unistd.h> #include <ctype.h> #include <sys/select.h> #include <sys/ioctl.h> #define ESC 27 #define INSERT 50 #define DELETE 51 #define PGUP 53 #define PGDN 54 #define ARROWRIGHT 67 #define ARROWLEFT 68 #define END 70 #define HOME 72 #define OTHER 79 #define BRACKETLEFT 91 #define TILDE 126 #define BACKSPACE 127 #define SIZE 30 static const int STDIN = 0; int kbhit(void) { int bytesWaiting; ioctl(STDIN,FIONREAD,&bytesWaiting); return bytesWaiting; } int main ( ) { char input[SIZE] = {''}; int insert = 0; int each = 0; int end = 0; int to = 0; int ch = 0; int row = 0; int col = 0; struct termios oldattr,newattr; //set terminal tcgetattr( STDIN,&oldattr ); newattr = oldattr; newattr.c_lflag &= ~( ICANON | ECHO ); tcsetattr( STDIN,&newattr ); setbuf(stdin,NULL); printf ( "33[2J");//clear screen printf ( "33[25;1H");//move cursor to row 25 col 1 printf ( "OVW"); printf ( "33[9;1H");//move cursor to row 9 col 1 printf ( "enter your text ");//prompt //printf ( "%s",input); printf ( "33[9;17H");//move cursor to row 9 col 17 col = 17; row = 9; while ( ( ch = getchar ()) != 'n') { if ( isprint( ch)) { if ( insert && each < end && end < SIZE-3) { //expand end++; for ( to = end; to >= each; to--) { input[to + 1] = input[to]; } printf ( "33[9;17H");//move cursor to row 9 col 12 printf ( "33[K");//erase to end of line printf ( "%s",input); } printf ( "33[%d;%dH",row,col); printf ( "%c",ch); input[each] = ch; each++; if ( each > end) { end = each; } coL++; if ( each == end) { input[each] = ''; } if ( each >= SIZE-1) { break; } continue; } if ( ch == BACKSPACE) { if ( each) { each--; col--; //contract for ( to = each; to <= end; to++) { input[to] = input[to + 1]; } end--; printf ( "33[9;17H");//move cursor to row 1 col 7 printf ( "33[K");//erase to end of line printf ( "%s",input); printf ( "33[%d;%dH",col); } } if ( ch == ESC) { if ( !kbhit ( )) { continue; } ch = getchar ( ); if ( ch == OTHER) { ch = getchar ( ); if ( ch == HOME) { col -= each; each = 0; printf ( "33[%d;%dH",col); ch = getchar ( ); } if ( ch == END) { col += end - each; each = end; printf ( "33[%d;%dH",col); ch = getchar ( ); } } if ( ch == BRACKETLEFT) { ch = getchar ( ); if ( ch == INSERT) { ch = getchar ( ); if ( ch == TILDE) { insert = !insert; printf ( "33[25;1H");//move cursor to row 25 col 1 if ( insert) { printf ( "INS"); } else { printf ( "OVW"); } printf ( "33[%d;%dH",col); } } if ( ch == DELETE) { ch = getchar ( ); if ( ch == TILDE) { //contract for ( to = each; to <= end; to++) { input[to] = input[to + 1]; } end--; printf ( "33[9;17H");//move cursor to row 10 col 1 printf ( "33[K");//erase to end of line printf ( "%s",col); } } if ( ch == ARROWRIGHT) { if ( each < end) { printf ( "33[C");//cursor right each++; coL++; } } if ( ch == ARROWLEFT) { if ( each) { printf ( "33[D");//cursor left each--; col--; } } } else { ungetc ( ch,stdin); } } } printf ( "nninput was [%s]n",input); printf ( "nnbyen"); //restore terminal tcsetattr( STDIN,&oldattr ); return 0; }

ANSI转义序列允许您随意在屏幕上移动光标。 这对于在shell下运行的程序生成的全屏用户界面是有用的,但也可以在提示中使用。 这不适用于不接受保存和恢复光标位置代码的终端仿真程序。 有关移动光标的转义序列的更多信息,请参阅光标移动 。

如果您需要更便携的解决方案,请使用curses ,它是一个终端控制库,用于管理应用程序在类Unix系统的字符终端上的显示。 执行系统上的curses库会根据终端类型发送正确的控制字符。 在ncurses中使用int wmove(WINDOW* win,int y,int x)来移动光标到一个新的位置。 有关如何在ncurses下编程的更多信息,请参见NCurses-programing-howto 。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐