我试图从一个小c程序中获取光标位置,所以在谷歌搜索后,我发现了这个ANSI代码\x1b[6n。它应该返回光标的x和y位置(如果我没有错的话),所以printf("\x1b[6n");给我输出:;1R我无法理解x和y位置的输出。编辑:平台是Linux(xterm)
\x1b[6n
printf("\x1b[6n");
;1R
vuktfyat1#
在 * 某些 * 终端上,例如DEC VT102和更高版本的VT,以及在许多终端仿真器上,特别是XTerm及其许多模仿品,发送Esc[6 n]将使终端响应Esc[row;columnR,其中 row 和 column 是 text 光标位置的十进制表示。所以你的终端模拟器 * 不 * 回复;1R;它是正确的回答,但读取行例程正在吃Esc[和十进制数字,直到;(并根据配置 Flink 屏幕或发出蜂鸣声)。下面是一个很好的Bash命令来说明:
out=''; \ echo $'\e[6n'; \ while read -n 1 -s -t 1; do out="$out$REPLY"; done < /dev/tty; \ echo -n "$out" | od -A x -t x1z -v
运行此命令可得到:
$ out=''; \ > echo $'\e[6n'; \ > while read -n 1 -s -t 1; do out="$out$REPLY"; done < /dev/tty; \ > echo -n "$out" | od -A x -t x1z -v 000000 1b 5b 31 36 3b 31 52 >.[16;1R< 000007
请注意,答案 * 不一定来自标准输入:即使标准输入被重定向,答案也来自终端。应询问者的要求,这里有一个小的C程序,它部分地复制了上面的scriptlet的功能。注意,该程序不处理将终端设置为原始模式和返回到熟模式;这必须在程序外处理,如下所示。
#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main (void) { int ttyfd = open ("/dev/tty", O_RDWR); if (ttyfd < 0) { printf ("Cannot open /devv/tty: errno = %d, %s\r\n", errno, strerror (errno)); exit (EXIT_FAILURE); } write (ttyfd, "\x1B[6n\n", 5); unsigned char answer[16]; size_t answerlen = 0; while (answerlen < sizeof (answer) - 1 && read (ttyfd, answer + answerlen, 1) == 1) if (answer [answerlen ++] == 'R') break; answer [answerlen] = '\0'; printf ("Answerback = \""); for (size_t i = 0; i < answerlen; ++ i) if (answer [i] < ' ' || '~' < answer [i]) printf ("\\x%02X", (unsigned char) answer [i]); else printf ("%c", answer [i]); printf ("\"\r\n"); return EXIT_SUCCESS; }
假设这个小程序是answerback.c:
answerback.c
$ gcc -Wall -Wextra answerback.c -o answerback $ stty raw -echo; ./answerback; stty sane Answerback = "\x1B[24;1R" $ _
dl5txlt92#
#include <stdio.h> #include <termios.h> int main() { int x = 0, y = 0; get_pos(&y, &x); printf("x:%d, y:%d\n", x, y); return 0; } int get_pos(int *y, int *x) { char buf[30]={0}; int ret, i, pow; char ch; *y = 0; *x = 0; struct termios term, restore; tcgetattr(0, &term); tcgetattr(0, &restore); term.c_lflag &= ~(ICANON|ECHO); tcsetattr(0, TCSANOW, &term); write(1, "\033[6n", 4); for( i = 0, ch = 0; ch != 'R'; i++ ) { ret = read(0, &ch, 1); if ( !ret ) { tcsetattr(0, TCSANOW, &restore); fprintf(stderr, "getpos: error reading response!\n"); return 1; } buf[i] = ch; printf("buf[%d]: \t%c \t%d\n", i, ch, ch); } if (i < 2) { tcsetattr(0, TCSANOW, &restore); printf("i < 2\n"); return(1); } for( i -= 2, pow = 1; buf[i] != ';'; i--, pow *= 10) *x = *x + ( buf[i] - '0' ) * pow; for( i-- , pow = 1; buf[i] != '['; i--, pow *= 10) *y = *y + ( buf[i] - '0' ) * pow; tcsetattr(0, TCSANOW, &restore); return 0; }
2条答案
按热度按时间vuktfyat1#
在 * 某些 * 终端上,例如DEC VT102和更高版本的VT,以及在许多终端仿真器上,特别是XTerm及其许多模仿品,发送Esc[6 n]将使终端响应Esc[row;columnR,其中 row 和 column 是 text 光标位置的十进制表示。
所以你的终端模拟器 * 不 * 回复
;1R
;它是正确的回答,但读取行例程正在吃Esc[和十进制数字,直到;(并根据配置 Flink 屏幕或发出蜂鸣声)。下面是一个很好的Bash命令来说明:
运行此命令可得到:
请注意,答案 * 不一定来自标准输入:即使标准输入被重定向,答案也来自终端。
应询问者的要求,这里有一个小的C程序,它部分地复制了上面的scriptlet的功能。注意,该程序不处理将终端设置为原始模式和返回到熟模式;这必须在程序外处理,如下所示。
假设这个小程序是
answerback.c
:dl5txlt92#